const char *gServiceName = NULL;
-int gsscon_passive_authenticate (int inSocket,
- gss_ctx_id_t *outGSSContext)
+int gsscon_passive_authenticate (int inSocket,
+ gss_buffer_desc inNameBuffer,
+ gss_ctx_id_t *outGSSContext,
+ client_cb_fn clientCb,
+ void *clientCbData)
{
int err = 0;
OM_uint32 majorStatus;
- OM_uint32 minorStatus = 0;
+ OM_uint32 minorStatus = 0, minorStatusToo = 0;
gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
-
+ gss_name_t clientName = GSS_C_NO_NAME, serviceName = GSS_C_NO_NAME;
+ gss_cred_id_t acceptorCredentials = NULL;
+ gss_buffer_desc clientDisplayName = {0, NULL};
char *inputTokenBuffer = NULL;
size_t inputTokenBufferLength = 0;
gss_buffer_desc inputToken; /* buffer received from the server */
if (inSocket < 0 ) { err = EINVAL; }
if (!outGSSContext) { err = EINVAL; }
-
+
+ if (!err) {
+ majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_import_name(serviceName)", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+
+ if (!err) {
+ majorStatus = gss_acquire_cred ( &minorStatus, serviceName,
+ GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_ACCEPT, &acceptorCredentials,
+ NULL /*mechs out*/, NULL /*time out*/);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+
/*
* The main authentication loop:
*
/*
* accept_sec_context does the actual work of taking the client's
- * request and generating an appropriate reply. Note that we pass
- * GSS_C_NO_CREDENTIAL for the service principal. This causes the
- * server to accept any service principal in the server's keytab,
- * which enables you to support multihomed hosts by having one key
- * in the keytab for each host identity the server responds on.
- *
- * However, since we may have more keys in the keytab than we want
- * the server to actually use, we will need to check which service
- * principal the client used after authentication succeeds. See
- * ServicePrincipalIsValidForService() for where you would put these
- * checks. We don't check here since if we stopped responding in the
- * middle of the authentication negotiation, the client would get an
- * EOF, and the user wouldn't know what went wrong.
- */
-
- printf ("Calling gss_accept_sec_context...\n");
+ * request and generating an appropriate reply. */
majorStatus = gss_accept_sec_context (&minorStatus,
&gssContext,
- GSS_C_NO_CREDENTIAL,
+ acceptorCredentials,
&inputToken,
GSS_C_NO_CHANNEL_BINDINGS,
- NULL /* client_name */,
- NULL /* actual_mech_type */,
+ &clientName,
+ NULL /* actual_mech_type */,
&outputToken,
NULL /* req_flags */,
NULL /* time_rec */,
err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
/* free the output token */
- gss_release_buffer (&minorStatus, &outputToken);
+ gss_release_buffer (&minorStatusToo, &outputToken);
}
}
err = minorStatus ? minorStatus : majorStatus;
}
}
-
+
+ if (!err) {
+ majorStatus = gss_display_name(&minorStatus, clientName, &clientDisplayName, NULL);
+ if (GSS_ERROR(majorStatus)) {
+ gsscon_print_gss_errors("gss_display_name", majorStatus, minorStatus);
+ err = EINVAL;
+ }
+ if (!err)
+ err = clientCb(clientName, &clientDisplayName, clientCbData);
+ }
+
if (!err) {
*outGSSContext = gssContext;
gssContext = NULL;
if (inputTokenBuffer) { free (inputTokenBuffer); }
if (gssContext != GSS_C_NO_CONTEXT) {
gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+if (clientName != GSS_C_NO_NAME)
+ gss_release_name(&minorStatus, &clientName);
+if (clientDisplayName.value != NULL)
+ gss_release_buffer(&minorStatus, &clientDisplayName);
+ gss_release_name( &minorStatus, &serviceName);
+ gss_release_cred( &minorStatus, &acceptorCredentials);
return err;
}
-/* --------------------------------------------------------------------------- */
-
-static int ServicePrincipalIsValidForService (const char *inServicePrincipal)
-{
- int err = 0;
- krb5_context context = NULL;
- krb5_principal principal = NULL;
-
- if (!inServicePrincipal) { err = EINVAL; }
-
- if (!err) {
- err = krb5_init_context (&context);
- }
-
- if (!err) {
- err = krb5_parse_name (context, inServicePrincipal, &principal);
- }
- if (!err) {
- /*
- * Here is where we check to see if the service principal the client
- * used is valid. Typically we would just check that the first component
- * is the name of the service provided by the server. This check exists
- * to make sure the server is using the correct key in its keytab since
- * we passed GSS_C_NO_CREDENTIAL into gss_accept_sec_context().
- */
- if (gServiceName && strcmp (gServiceName,
- krb5_princ_name (context, principal)->data) != 0) {
- err = KRB5KRB_AP_WRONG_PRINC;
- }
- }
-
- if (principal) { krb5_free_principal (context, principal); }
- if (context ) { krb5_free_context (context); }
-
- return err;
-}
/* --------------------------------------------------------------------------- */
static int ClientPrincipalIsAuthorizedForService (const char *inClientPrincipal)
{
int err = 0;
- krb5_context context = NULL;
- krb5_principal principal = NULL;
-
- if (!inClientPrincipal) { err = EINVAL; }
-
- if (!err) {
- err = krb5_init_context (&context);
- }
-
- if (!err) {
- err = krb5_parse_name (context, inClientPrincipal, &principal);
- }
-
- if (!err) {
/*
* Here is where the server checks to see if the client principal should
* be allowed to use your service. Typically it should check both the name
* realm may be trying to contact your service.
*/
err = 0;
- }
+
- if (principal) { krb5_free_principal (context, principal); }
- if (context ) { krb5_free_context (context); }
return err;
}
if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
}
- if (!err) {
- /* Pull the service principal string out of the gss name */
- gss_buffer_desc nameToken;
-
- majorStatus = gss_display_name (&minorStatus,
- serviceName,
- &nameToken,
- NULL);
- if (majorStatus != GSS_S_COMPLETE) {
- err = minorStatus ? minorStatus : majorStatus;
- }
-
if (!err) {
- servicePrincipal = malloc (nameToken.length + 1);
- if (servicePrincipal == NULL) { err = ENOMEM; }
- }
-
- if (!err) {
- memcpy (servicePrincipal, nameToken.value, nameToken.length);
- servicePrincipal[nameToken.length] = '\0';
- }
+ // /* Pull the service principal string out of the gss name */
+ // gss_buffer_desc nameToken;
+ //
+ // majorStatus = gss_display_name (&minorStatus,
+ // serviceName,
+ // &nameToken,
+ // NULL);
+ // if (majorStatus != GSS_S_COMPLETE) {
+ // err = minorStatus ? minorStatus : majorStatus;
+ // }
+ //
+ // if (!err) {
+ // servic7ePrincipal = malloc (nameToken.length + 1);
+ // if (servicePrincipal == NULL) { err = ENOMEM; }
+ // }
+ //
+ // if (!err) {
+ // memcpy (servicePrincipal, nameToken.value, nameToken.length);
+ // servicePrincipal[nameToken.length] = '\0';
+ // }
- if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
- }
+ // if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
+ // }
- if (!err) {
- int authorizationErr = ServicePrincipalIsValidForService (servicePrincipal);
+
+ int authorizationErr = 0;
+ authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);
+
+
- if (!authorizationErr) {
- authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);
+// printf ("'%s' is%s authorized for service '%s'\n",
+// clientPrincipal, authorizationErr ? " NOT" : "", servicePrincipal);
+//
+ *outAuthorized = !authorizationErr;
+ *outAuthorizationError = authorizationErr;
}
-
- printf ("'%s' is%s authorized for service '%s'\n",
- clientPrincipal, authorizationErr ? " NOT" : "", servicePrincipal);
-
- *outAuthorized = !authorizationErr;
- *outAuthorizationError = authorizationErr;
- }
if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
if (clientName ) { gss_release_name (&minorStatus, &clientName); }