Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F78225300
kerberosgss.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Aug 19, 06:29
Size
20 KB
Mime Type
text/x-c
Expires
Wed, Aug 21, 06:29 (1 d, 21 h)
Engine
blob
Format
Raw Data
Handle
19986123
Attached To
R2664 SHRINE MedCo Fork
kerberosgss.c
View Options
/**
* Copyright (c) 2006-2010 Apple Inc. All rights reserved.
*
* 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.
**/
#include "kerberosgss.h"
#include "base64.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
static
void
set_gss_error
(
OM_uint32
err_maj
,
OM_uint32
err_min
);
/*extern PyObject *GssException_class;
extern PyObject *KrbException_class;
char* server_principal_details(const char* service, const char* hostname)
{
char match[1024];
int match_len = 0;
char* result = NULL;
int code;
krb5_context kcontext;
krb5_keytab kt = NULL;
krb5_kt_cursor cursor = NULL;
krb5_keytab_entry entry;
char* pname = NULL;
// Generate the principal prefix we want to match
snprintf(match, 1024, "%s/%s@", service, hostname);
match_len = strlen(match);
code = krb5_init_context(&kcontext);
if (code)
{
PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
"Cannot initialize Kerberos5 context", code));
return NULL;
}
if ((code = krb5_kt_default(kcontext, &kt)))
{
PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
"Cannot get default keytab", code));
goto end;
}
if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor)))
{
PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
"Cannot get sequence cursor from keytab", code));
goto end;
}
while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0)
{
if ((code = krb5_unparse_name(kcontext, entry.principal, &pname)))
{
PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
"Cannot parse principal name from keytab", code));
goto end;
}
if (strncmp(pname, match, match_len) == 0)
{
result = malloc(strlen(pname) + 1);
strcpy(result, pname);
krb5_free_unparsed_name(kcontext, pname);
krb5_free_keytab_entry_contents(kcontext, &entry);
break;
}
krb5_free_unparsed_name(kcontext, pname);
krb5_free_keytab_entry_contents(kcontext, &entry);
}
if (result == NULL)
{
PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
"Principal not found in keytab", -1));
}
end:
if (cursor)
krb5_kt_end_seq_get(kcontext, kt, &cursor);
if (kt)
krb5_kt_close(kcontext, kt);
krb5_free_context(kcontext);
return result;
}
*/
gss_client_response
*
authenticate_gss_client_init
(
const
char
*
service
,
long
int
gss_flags
,
gss_client_state
*
state
)
{
OM_uint32
maj_stat
;
OM_uint32
min_stat
;
gss_buffer_desc
name_token
=
GSS_C_EMPTY_BUFFER
;
gss_client_response
*
response
=
NULL
;
int
ret
=
AUTH_GSS_COMPLETE
;
state
->
server_name
=
GSS_C_NO_NAME
;
state
->
context
=
GSS_C_NO_CONTEXT
;
state
->
gss_flags
=
gss_flags
;
state
->
username
=
NULL
;
state
->
response
=
NULL
;
// Import server name first
name_token
.
length
=
strlen
(
service
);
name_token
.
value
=
(
char
*
)
service
;
maj_stat
=
gss_import_name
(
&
min_stat
,
&
name_token
,
gss_krb5_nt_service_name
,
&
state
->
server_name
);
if
(
GSS_ERROR
(
maj_stat
))
{
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
AUTH_GSS_ERROR
;
goto
end
;
}
end:
if
(
response
==
NULL
)
{
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
response
->
return_code
=
ret
;
}
return
response
;
}
gss_client_response
*
authenticate_gss_client_clean
(
gss_client_state
*
state
)
{
OM_uint32
min_stat
;
int
ret
=
AUTH_GSS_COMPLETE
;
gss_client_response
*
response
=
NULL
;
if
(
state
->
context
!=
GSS_C_NO_CONTEXT
)
gss_delete_sec_context
(
&
min_stat
,
&
state
->
context
,
GSS_C_NO_BUFFER
);
if
(
state
->
server_name
!=
GSS_C_NO_NAME
)
gss_release_name
(
&
min_stat
,
&
state
->
server_name
);
if
(
state
->
username
!=
NULL
)
{
free
(
state
->
username
);
state
->
username
=
NULL
;
}
if
(
state
->
response
!=
NULL
)
{
free
(
state
->
response
);
state
->
response
=
NULL
;
}
if
(
response
==
NULL
)
{
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
response
->
return_code
=
ret
;
}
return
response
;
}
gss_client_response
*
authenticate_gss_client_step
(
gss_client_state
*
state
,
const
char
*
challenge
)
{
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
;
gss_client_response
*
response
=
NULL
;
// Always clear out the old response
if
(
state
->
response
!=
NULL
)
{
free
(
state
->
response
);
state
->
response
=
NULL
;
}
// If there is a challenge (data from the server) we need to give it to GSS
if
(
challenge
&&
*
challenge
)
{
int
len
;
input_token
.
value
=
base64_decode
(
challenge
,
&
len
);
input_token
.
length
=
len
;
}
// Do GSSAPI step
maj_stat
=
gss_init_sec_context
(
&
min_stat
,
GSS_C_NO_CREDENTIAL
,
&
state
->
context
,
state
->
server_name
,
GSS_C_NO_OID
,
(
OM_uint32
)
state
->
gss_flags
,
0
,
GSS_C_NO_CHANNEL_BINDINGS
,
&
input_token
,
NULL
,
&
output_token
,
NULL
,
NULL
);
if
((
maj_stat
!=
GSS_S_COMPLETE
)
&&
(
maj_stat
!=
GSS_S_CONTINUE_NEEDED
))
{
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
AUTH_GSS_ERROR
;
goto
end
;
}
ret
=
(
maj_stat
==
GSS_S_COMPLETE
)
?
AUTH_GSS_COMPLETE
:
AUTH_GSS_CONTINUE
;
// 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
);
}
// Try to get the user name if we have completed all GSS operations
if
(
ret
==
AUTH_GSS_COMPLETE
)
{
gss_name_t
gssuser
=
GSS_C_NO_NAME
;
maj_stat
=
gss_inquire_context
(
&
min_stat
,
state
->
context
,
&
gssuser
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
GSS_ERROR
(
maj_stat
))
{
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
AUTH_GSS_ERROR
;
goto
end
;
}
gss_buffer_desc
name_token
;
name_token
.
length
=
0
;
maj_stat
=
gss_display_name
(
&
min_stat
,
gssuser
,
&
name_token
,
NULL
);
if
(
GSS_ERROR
(
maj_stat
))
{
if
(
name_token
.
value
)
gss_release_buffer
(
&
min_stat
,
&
name_token
);
gss_release_name
(
&
min_stat
,
&
gssuser
);
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
AUTH_GSS_ERROR
;
goto
end
;
}
else
{
state
->
username
=
(
char
*
)
malloc
(
name_token
.
length
+
1
);
strncpy
(
state
->
username
,
(
char
*
)
name_token
.
value
,
name_token
.
length
);
state
->
username
[
name_token
.
length
]
=
0
;
gss_release_buffer
(
&
min_stat
,
&
name_token
);
gss_release_name
(
&
min_stat
,
&
gssuser
);
}
}
end:
if
(
output_token
.
value
)
gss_release_buffer
(
&
min_stat
,
&
output_token
);
if
(
input_token
.
value
)
free
(
input_token
.
value
);
if
(
response
==
NULL
)
{
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
response
->
return_code
=
ret
;
}
// Return the response
return
response
;
}
gss_client_response
*
authenticate_gss_client_unwrap
(
gss_client_state
*
state
,
const
char
*
challenge
)
{
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
;
gss_client_response
*
response
=
NULL
;
int
ret
=
AUTH_GSS_CONTINUE
;
// Always clear out the old response
if
(
state
->
response
!=
NULL
)
{
free
(
state
->
response
);
state
->
response
=
NULL
;
}
// If there is a challenge (data from the server) we need to give it to GSS
if
(
challenge
&&
*
challenge
)
{
int
len
;
input_token
.
value
=
base64_decode
(
challenge
,
&
len
);
input_token
.
length
=
len
;
}
// Do GSSAPI step
maj_stat
=
gss_unwrap
(
&
min_stat
,
state
->
context
,
&
input_token
,
&
output_token
,
NULL
,
NULL
);
if
(
maj_stat
!=
GSS_S_COMPLETE
)
{
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
AUTH_GSS_ERROR
;
goto
end
;
}
else
{
ret
=
AUTH_GSS_COMPLETE
;
}
// Grab the client response
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
);
if
(
input_token
.
value
)
free
(
input_token
.
value
);
if
(
response
==
NULL
)
{
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
response
->
return_code
=
ret
;
}
// Return the response
return
response
;
}
gss_client_response
*
authenticate_gss_client_wrap
(
gss_client_state
*
state
,
const
char
*
challenge
,
const
char
*
user
)
{
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
;
gss_client_response
*
response
=
NULL
;
char
buf
[
4096
],
server_conf_flags
;
unsigned
long
buf_size
;
// Always clear out the old response
if
(
state
->
response
!=
NULL
)
{
free
(
state
->
response
);
state
->
response
=
NULL
;
}
if
(
challenge
&&
*
challenge
)
{
int
len
;
input_token
.
value
=
base64_decode
(
challenge
,
&
len
);
input_token
.
length
=
len
;
}
if
(
user
)
{
// get bufsize
server_conf_flags
=
((
char
*
)
input_token
.
value
)[
0
];
((
char
*
)
input_token
.
value
)[
0
]
=
0
;
buf_size
=
ntohl
(
*
((
long
*
)
input_token
.
value
));
free
(
input_token
.
value
);
#ifdef PRINTFS
printf
(
"User: %s, %c%c%c
\n
"
,
user
,
server_conf_flags
&
GSS_AUTH_P_NONE
?
'N'
:
'-'
,
server_conf_flags
&
GSS_AUTH_P_INTEGRITY
?
'I'
:
'-'
,
server_conf_flags
&
GSS_AUTH_P_PRIVACY
?
'P'
:
'-'
);
printf
(
"Maximum GSS token size is %ld
\n
"
,
buf_size
);
#endif
// agree to terms (hack!)
buf_size
=
htonl
(
buf_size
);
// not relevant without integrity/privacy
memcpy
(
buf
,
&
buf_size
,
4
);
buf
[
0
]
=
GSS_AUTH_P_NONE
;
// server decides if principal can log in as user
strncpy
(
buf
+
4
,
user
,
sizeof
(
buf
)
-
4
);
input_token
.
value
=
buf
;
input_token
.
length
=
4
+
strlen
(
user
);
}
// 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
)
{
response
=
gss_error
(
maj_stat
,
min_stat
);
response
->
return_code
=
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
);
if
(
response
==
NULL
)
{
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
response
->
return_code
=
ret
;
}
// Return the response
return
response
;
}
int
authenticate_gss_server_init
(
const
char
*
service
,
gss_server_state
*
state
)
{
OM_uint32
maj_stat
;
OM_uint32
min_stat
;
gss_buffer_desc
name_token
=
GSS_C_EMPTY_BUFFER
;
int
ret
=
AUTH_GSS_COMPLETE
;
state
->
context
=
GSS_C_NO_CONTEXT
;
state
->
server_name
=
GSS_C_NO_NAME
;
state
->
client_name
=
GSS_C_NO_NAME
;
state
->
server_creds
=
GSS_C_NO_CREDENTIAL
;
state
->
client_creds
=
GSS_C_NO_CREDENTIAL
;
state
->
username
=
NULL
;
state
->
targetname
=
NULL
;
state
->
response
=
NULL
;
// Server name may be empty which means we aren't going to create our own creds
size_t
service_len
=
strlen
(
service
);
if
(
service_len
!=
0
)
{
// Import server name first
name_token
.
length
=
strlen
(
service
);
name_token
.
value
=
(
char
*
)
service
;
maj_stat
=
gss_import_name
(
&
min_stat
,
&
name_token
,
GSS_C_NT_HOSTBASED_SERVICE
,
&
state
->
server_name
);
if
(
GSS_ERROR
(
maj_stat
))
{
set_gss_error
(
maj_stat
,
min_stat
);
ret
=
AUTH_GSS_ERROR
;
goto
end
;
}
// Get credentials
maj_stat
=
gss_acquire_cred
(
&
min_stat
,
state
->
server_name
,
GSS_C_INDEFINITE
,
GSS_C_NO_OID_SET
,
GSS_C_ACCEPT
,
&
state
->
server_creds
,
NULL
,
NULL
);
if
(
GSS_ERROR
(
maj_stat
))
{
set_gss_error
(
maj_stat
,
min_stat
);
ret
=
AUTH_GSS_ERROR
;
goto
end
;
}
}
end:
return
ret
;
}
int
authenticate_gss_server_clean
(
gss_server_state
*
state
)
{
OM_uint32
min_stat
;
int
ret
=
AUTH_GSS_COMPLETE
;
if
(
state
->
context
!=
GSS_C_NO_CONTEXT
)
gss_delete_sec_context
(
&
min_stat
,
&
state
->
context
,
GSS_C_NO_BUFFER
);
if
(
state
->
server_name
!=
GSS_C_NO_NAME
)
gss_release_name
(
&
min_stat
,
&
state
->
server_name
);
if
(
state
->
client_name
!=
GSS_C_NO_NAME
)
gss_release_name
(
&
min_stat
,
&
state
->
client_name
);
if
(
state
->
server_creds
!=
GSS_C_NO_CREDENTIAL
)
gss_release_cred
(
&
min_stat
,
&
state
->
server_creds
);
if
(
state
->
client_creds
!=
GSS_C_NO_CREDENTIAL
)
gss_release_cred
(
&
min_stat
,
&
state
->
client_creds
);
if
(
state
->
username
!=
NULL
)
{
free
(
state
->
username
);
state
->
username
=
NULL
;
}
if
(
state
->
targetname
!=
NULL
)
{
free
(
state
->
targetname
);
state
->
targetname
=
NULL
;
}
if
(
state
->
response
!=
NULL
)
{
free
(
state
->
response
);
state
->
response
=
NULL
;
}
return
ret
;
}
/*int authenticate_gss_server_step(gss_server_state *state, const char *challenge)
{
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 there is a challenge (data from the server) we need to give it to GSS
if (challenge && *challenge)
{
int len;
input_token.value = base64_decode(challenge, &len);
input_token.length = len;
}
else
{
PyErr_SetString(KrbException_class, "No challenge parameter in request from client");
ret = AUTH_GSS_ERROR;
goto end;
}
maj_stat = gss_accept_sec_context(&min_stat,
&state->context,
state->server_creds,
&input_token,
GSS_C_NO_CHANNEL_BINDINGS,
&state->client_name,
NULL,
&output_token,
NULL,
NULL,
&state->client_creds);
if (GSS_ERROR(maj_stat))
{
set_gss_error(maj_stat, min_stat);
ret = AUTH_GSS_ERROR;
goto end;
}
// Grab the server response to send back to the client
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);
}
// Get the user name
maj_stat = gss_display_name(&min_stat, state->client_name, &output_token, NULL);
if (GSS_ERROR(maj_stat))
{
set_gss_error(maj_stat, min_stat);
ret = AUTH_GSS_ERROR;
goto end;
}
state->username = (char *)malloc(output_token.length + 1);
strncpy(state->username, (char*) output_token.value, output_token.length);
state->username[output_token.length] = 0;
// Get the target name if no server creds were supplied
if (state->server_creds == GSS_C_NO_CREDENTIAL)
{
gss_name_t target_name = GSS_C_NO_NAME;
maj_stat = gss_inquire_context(&min_stat, state->context, NULL, &target_name, NULL, NULL, NULL, NULL, NULL);
if (GSS_ERROR(maj_stat))
{
set_gss_error(maj_stat, min_stat);
ret = AUTH_GSS_ERROR;
goto end;
}
maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL);
if (GSS_ERROR(maj_stat))
{
set_gss_error(maj_stat, min_stat);
ret = AUTH_GSS_ERROR;
goto end;
}
state->targetname = (char *)malloc(output_token.length + 1);
strncpy(state->targetname, (char*) output_token.value, output_token.length);
state->targetname[output_token.length] = 0;
}
ret = AUTH_GSS_COMPLETE;
end:
if (output_token.length)
gss_release_buffer(&min_stat, &output_token);
if (input_token.value)
free(input_token.value);
return ret;
}
*/
static
void
set_gss_error
(
OM_uint32
err_maj
,
OM_uint32
err_min
)
{
OM_uint32
maj_stat
,
min_stat
;
OM_uint32
msg_ctx
=
0
;
gss_buffer_desc
status_string
;
char
buf_maj
[
512
];
char
buf_min
[
512
];
do
{
maj_stat
=
gss_display_status
(
&
min_stat
,
err_maj
,
GSS_C_GSS_CODE
,
GSS_C_NO_OID
,
&
msg_ctx
,
&
status_string
);
if
(
GSS_ERROR
(
maj_stat
))
break
;
strncpy
(
buf_maj
,
(
char
*
)
status_string
.
value
,
sizeof
(
buf_maj
));
gss_release_buffer
(
&
min_stat
,
&
status_string
);
maj_stat
=
gss_display_status
(
&
min_stat
,
err_min
,
GSS_C_MECH_CODE
,
GSS_C_NULL_OID
,
&
msg_ctx
,
&
status_string
);
if
(
!
GSS_ERROR
(
maj_stat
))
{
strncpy
(
buf_min
,
(
char
*
)
status_string
.
value
,
sizeof
(
buf_min
));
gss_release_buffer
(
&
min_stat
,
&
status_string
);
}
}
while
(
!
GSS_ERROR
(
maj_stat
)
&&
msg_ctx
!=
0
);
}
gss_client_response
*
gss_error
(
OM_uint32
err_maj
,
OM_uint32
err_min
)
{
OM_uint32
maj_stat
,
min_stat
;
OM_uint32
msg_ctx
=
0
;
gss_buffer_desc
status_string
;
char
*
buf_maj
=
calloc
(
512
,
sizeof
(
char
));
char
*
buf_min
=
calloc
(
512
,
sizeof
(
char
));
char
*
message
=
NULL
;
gss_client_response
*
response
=
calloc
(
1
,
sizeof
(
gss_client_response
));
do
{
maj_stat
=
gss_display_status
(
&
min_stat
,
err_maj
,
GSS_C_GSS_CODE
,
GSS_C_NO_OID
,
&
msg_ctx
,
&
status_string
);
if
(
GSS_ERROR
(
maj_stat
))
break
;
strncpy
(
buf_maj
,
(
char
*
)
status_string
.
value
,
512
);
gss_release_buffer
(
&
min_stat
,
&
status_string
);
maj_stat
=
gss_display_status
(
&
min_stat
,
err_min
,
GSS_C_MECH_CODE
,
GSS_C_NULL_OID
,
&
msg_ctx
,
&
status_string
);
if
(
!
GSS_ERROR
(
maj_stat
))
{
strncpy
(
buf_min
,
(
char
*
)
status_string
.
value
,
512
);
gss_release_buffer
(
&
min_stat
,
&
status_string
);
}
}
while
(
!
GSS_ERROR
(
maj_stat
)
&&
msg_ctx
!=
0
);
// Join the strings
message
=
calloc
(
1026
,
1
);
// Join the two messages
sprintf
(
message
,
"%s, %s"
,
buf_maj
,
buf_min
);
// Free data
free
(
buf_min
);
free
(
buf_maj
);
// Set the message
response
->
message
=
message
;
// Return the message
return
response
;
}
Event Timeline
Log In to Comment