Ejemplo n.º 1
0
OM_uint32
ntlm_gss_inquire_context(
			OM_uint32	*minor_status,
			const gss_ctx_id_t context_handle,
			gss_name_t	*src_name,
			gss_name_t	*targ_name,
			OM_uint32	*lifetime_rec,
			gss_OID		*mech_type,
			OM_uint32	*ctx_flags,
			int		*locally_initiated,
			int		*opened)
{
	OM_uint32 ret = GSS_S_COMPLETE;

	ret = gss_inquire_context(minor_status,
				context_handle,
				src_name,
				targ_name,
				lifetime_rec,
				NULL,
				ctx_flags,
				locally_initiated,
				opened);

	if (mech_type)
		*mech_type = context_handle->mech_type;

	return (ret);
}
Ejemplo n.º 2
0
static void log_service_name(gss_ctx_id_t context)
{
    OM_uint32 major_status = 0, minor_status = 0;
    gss_name_t service_name;
    gss_buffer_desc service_name_buffer;

    major_status = gss_inquire_context(&minor_status,
                                       context,
                                       NULL,
                                       &service_name,
                                       NULL,
                                       NULL,
                                       NULL,
                                       NULL,
                                       NULL);
    if (major_status != GSS_S_COMPLETE) {
        log_status("gss_inquire_context", major_status, minor_status);
        return;
    }

    major_status = gss_display_name(&minor_status,
                                    service_name,
                                    &service_name_buffer,
                                    NULL);
    if (major_status == GSS_S_COMPLETE) {
        LOG_LOGINCONT(log_debug,
                      "service principal is `%s'",
                      service_name_buffer.value);

        gss_release_buffer(&minor_status, &service_name_buffer);
    } else
        log_status("gss_display_name", major_status, minor_status);

    gss_release_name(&minor_status, &service_name);
}
Ejemplo n.º 3
0
uint32_t
sapgss_inquire_context(
    uint32_t *minor_status,
    gss_ctx_id_t context_handle,
    gss_name_t *src_name,
    gss_name_t *targ_name,
    uint32_t *lifetime_rec,
    sapgss_OID *mech_type,
    uint32_t *ctx_flags,
    int *locally_initiated,
    int *open)
{
    gss_OID mech_type_loc;
    uint32_t major_status;
    int ret;

    major_status = gss_inquire_context(minor_status, context_handle, src_name,
				       targ_name, lifetime_rec, &mech_type_loc,
				       ctx_flags, locally_initiated, open);
    ret = gss_OID_loc_to_sap(mech_type_loc, mech_type);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    *mech_type = &gss_mech_krb5;
    return major_status;
}
Ejemplo n.º 4
0
static inline bool
authgss_ctx_expired(struct svc_rpc_gss_data *gd)
{
	OM_uint32 maj_stat, min_stat;
	maj_stat =
	    gss_inquire_context(&min_stat, gd->ctx, NULL, NULL, NULL, NULL,
				NULL, NULL, NULL);
	return (maj_stat == GSS_S_CONTEXT_EXPIRED);
}
Ejemplo n.º 5
0
Archivo: gsi.c Proyecto: ddk50/gfarm_v2
int
gfarmGssInitiateSecurityContextResult(
    struct gfarmGssInitiateSecurityContextState *state, gss_ctx_id_t *scPtr,
    OM_uint32 *majStatPtr, OM_uint32 *minStatPtr, gss_name_t *remoteNamePtr)
{
    int ret;
    OM_uint32 minStat2;

    assert(GSS_ERROR(state->majStat) || state->completed);

    if (state->itPtr->length > 0) {
	(void)gss_release_buffer(&minStat2, state->itPtr);
    }
    if (state->otPtr->length > 0) {
	(void)gss_release_buffer(&minStat2, state->otPtr);
    }

    if (state->majStat == GSS_S_COMPLETE && remoteNamePtr != NULL) {
	state->majStat = gss_inquire_context(&state->minStat,
					     state->sc,
					     NULL,
					     remoteNamePtr,
					     NULL,
					     NULL,
					     NULL,
					     NULL,
					     NULL);
    }

    gfarm_event_free(state->readable);
    gfarm_event_free(state->writable);

    if (majStatPtr != NULL)
	*majStatPtr = state->majStat;
    if (minStatPtr != NULL)
	*minStatPtr = state->minStat;

    if (state->majStat == GSS_S_COMPLETE) {
	*scPtr = state->sc;
    } else if (state->sc != GSS_C_NO_CONTEXT) {
	gss_delete_sec_context(&minStat2, &state->sc, GSS_C_NO_BUFFER);
    }

    ret = state->majStat == GSS_S_COMPLETE ? 1 : -1;
    free(state);

    if (ret == -1) {
	gflog_debug(GFARM_MSG_1000802,
		"failed to get result of initiate security context");
    }

    return ret;
}
Ejemplo n.º 6
0
char * Condor_Auth_X509::get_server_info()
{
    OM_uint32	major_status = 0;
    OM_uint32	minor_status = 0;            
    OM_uint32   lifetime, flags;
    gss_OID     mech, name_type;
    gss_buffer_desc name_buf;
    char *      server = NULL;
    
    // Now, we do some authorization work 
    major_status = gss_inquire_context(&minor_status,
                                       context_handle,
                                       NULL,    
                                       &m_gss_server_name,
                                       &lifetime,
                                       &mech, 
                                       &flags, 
                                       NULL,
                                       NULL);
    if (major_status != GSS_S_COMPLETE) {
        dprintf(D_SECURITY, "Unable to obtain target principal name\n");
        return NULL;
    }

	major_status = gss_display_name(&minor_status,
									m_gss_server_name,
									&name_buf,
									&name_type);
	if( major_status != GSS_S_COMPLETE) {
		dprintf(D_SECURITY, "Unable to convert target principal name\n");
		return NULL;
	}

	server = new char[name_buf.length+1];
	memset(server, 0, name_buf.length+1);
	memcpy(server, name_buf.value, name_buf.length);
	gss_release_buffer( &minor_status, &name_buf );

    return server;
}   
const char * getGSSAPISrcName( gss_ctx_id_t * inContext )
{
	char *		theGSSAPISrcName = 0;
	OM_uint32	theMajorStatus;
	OM_uint32	theMinorStatus;
	gss_name_t	theSrcName;

	theMajorStatus = gss_inquire_context( &theMinorStatus,
										  *inContext,
										  &theSrcName,
										  0,
										  0,
										  0,
										  0,
										  0,
										  0 );
	if ( theMajorStatus == GSS_S_COMPLETE )
	{
		gss_buffer_desc theSrcNameBuffer;
		theMajorStatus = gss_display_name( &theMinorStatus,
										   theSrcName,
										   &theSrcNameBuffer,
										   0 );
		if ( theMajorStatus == GSS_S_COMPLETE )
		{
			int theSize			= theSrcNameBuffer.length + 1;
			theGSSAPISrcName	= ( char * )malloc( theSize );
			if ( theGSSAPISrcName != 0 )
			{
				snprintf( theGSSAPISrcName,
						  theSize,
						  "%s",
						  ( char *)theSrcNameBuffer.value );
			}
			gss_release_buffer( &theMinorStatus, &theSrcNameBuffer );	
		}
	}	
	return theGSSAPISrcName;
}
Ejemplo n.º 8
0
OM_uint32 _gss_spnego_inquire_context (
            OM_uint32 * minor_status,
            const gss_ctx_id_t context_handle,
            gss_name_t * src_name,
            gss_name_t * targ_name,
            OM_uint32 * lifetime_rec,
            gss_OID * mech_type,
            OM_uint32 * ctx_flags,
            int * locally_initiated,
            int * open_context
           )
{
    gssspnego_ctx ctx;

    *minor_status = 0;

    if (context_handle == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    ctx = (gssspnego_ctx)context_handle;

    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    return gss_inquire_context(minor_status,
			       ctx->negotiated_ctx_id,
			       src_name,
			       targ_name,
			       lifetime_rec,
			       mech_type,
			       ctx_flags,
			       locally_initiated,
			       open_context);
}
Ejemplo n.º 9
0
int verify_context(gss_ctx_id_t context_handle)
{
	OM_uint32       major_status = 0;
	OM_uint32       minor_status = 0;
	OM_uint32       ret_flags = 0;
	gss_name_t	target_name = GSS_C_NO_NAME;
	gss_name_t	src_name = GSS_C_NO_NAME;
	gss_buffer_desc	name_buffer  = GSS_C_EMPTY_BUFFER;

	char	*target_name_str = NULL;
	char	*src_name_str = NULL;
        int	DN_cleaned = 0;
	int	CNoffset, i;

        const char *ignored_CNs[] = {", CN=proxy", ", CN=limited proxy"};

	major_status = gss_inquire_context(
		&minor_status, /* minor_status */
		context_handle, /* context_handle */
		&src_name,  /* The client principal name */
		&target_name, /* The server principal name */
		NULL, /* don't need user_to_user */
		NULL, /* don't need user_to_user */
		NULL, /* don't need user_to_user */
		NULL, /* don't need user_to_user */
		NULL  /* don't need user_to_user */
		);
	CHECK_GLOBUS_CALL("GSS context inquire failure ", 1, major_status);

	/* Get the server principal name */
	major_status = gss_display_name(
		&minor_status,
		target_name, 
		&name_buffer,
		NULL);
	CHECK_GLOBUS_CALL("GSS display_name failure ", 1, major_status);
	if ((target_name_str = (char *)malloc((name_buffer.length + 1) * sizeof(char))) == NULL)
	{
		fprintf(stderr, "verify_context(): Out of memory\n");
		return(1);
	}
	memcpy(target_name_str, name_buffer.value, name_buffer.length);
	target_name_str[name_buffer.length] = '\0';
	major_status = gss_release_name(&minor_status, &target_name);
	major_status = gss_release_buffer(&minor_status, &name_buffer);

	/* Get the client principal name */
	major_status = gss_display_name(
		&minor_status,
		src_name, 
		&name_buffer,
		NULL);
	CHECK_GLOBUS_CALL("GSS display_name failure ", 1, major_status);
	if ((src_name_str = (char *)malloc((name_buffer.length + 1) * sizeof(char))) == NULL)
	{
		fprintf(stderr, "verify_context(): Out of memory\n");
		return(1);
	}
	memcpy(src_name_str, name_buffer.value, name_buffer.length);
	src_name_str[name_buffer.length] = '\0';
	major_status = gss_release_name(&minor_status, &target_name);
	major_status = gss_release_buffer(&minor_status, &name_buffer);

	/* Strip trailing (limited) proxy CNs */
	/* This is only needed (and effective) with very old */
	/* versions of Globus. More recent versions return the */
        /* pruned 'globusid' base name, making this stripping */
        /* both useless and harmless. */
        while (!DN_cleaned)
	{
		DN_cleaned = 1;
		for (i = 0; i < sizeof(ignored_CNs)/sizeof(char *); i++)
		{
			CNoffset = strlen(src_name_str) - strlen(ignored_CNs[i]);
			if (strcmp(src_name_str + CNoffset, ignored_CNs[i]) == 0)
			{
				src_name_str[CNoffset] = '\0';
				DN_cleaned = 0;
			}
		}
	}
        DN_cleaned = 0;
        while (!DN_cleaned)
	{
		DN_cleaned = 1;
		for (i = 0; i < sizeof(ignored_CNs)/sizeof(char *); i++)
		{
			CNoffset = strlen(target_name_str) - strlen(ignored_CNs[i]);
			if (strcmp(target_name_str + CNoffset, ignored_CNs[i]) == 0)
			{
				target_name_str[CNoffset] = '\0';
				DN_cleaned = 0;
			}
		}
	}


	return (strcmp(src_name_str, target_name_str));
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
Archivo: gsi.c Proyecto: ddk50/gfarm_v2
int
gfarmGssInitiateSecurityContext(int fd, const gss_name_t acceptorName,
    gss_cred_id_t cred, OM_uint32 reqFlag, gss_ctx_id_t *scPtr,
    OM_uint32 *majStatPtr, OM_uint32 *minStatPtr, gss_name_t *remoteNamePtr)
{
    OM_uint32 majStat;
    OM_uint32 minStat, minStat2;
    OM_uint32 retFlag = 0;

    gss_buffer_desc inputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t itPtr = &inputToken;
    
    gss_buffer_desc outputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t otPtr = &outputToken;

    gss_OID *actualMechType = NULL;
    OM_uint32 timeRet;

    int tknStat;

    static const char diag[] = "gfarmGssInitiateSecurityContext()";

    *scPtr = GSS_C_NO_CONTEXT;

    /*
     * Implementation specification:
     * In gfarm, an initiator must reveal own identity to an acceptor.
     */
    if ((reqFlag & GSS_C_ANON_FLAG) == GSS_C_ANON_FLAG) {
	/* It is a bit safer to deny the request than to silently ignore it */
	gflog_auth_error(GFARM_MSG_1000618,
	    "gfarmGssInitiateSecurityContext(): "
	    "GSS_C_ANON_FLAG is not allowed");
	majStat = GSS_S_UNAVAILABLE;
	minStat = GFSL_DEFAULT_MINOR_ERROR;
	goto Done;
    }

    while (1) {
	gfarm_mutex_lock(&gss_mutex, diag, gssDiag);
	majStat = gss_init_sec_context(&minStat,
				       cred,
				       scPtr,
				       acceptorName,
				       GSS_C_NO_OID,
				       reqFlag,
				       0,
				       GSS_C_NO_CHANNEL_BINDINGS,
				       itPtr,
				       actualMechType,
				       otPtr,
				       &retFlag,
				       &timeRet);
	gfarm_mutex_unlock(&gss_mutex, diag, gssDiag);
	
	if (itPtr->length > 0)
	    gss_release_buffer(&minStat2, itPtr);

	if (otPtr->length > 0) {
	    tknStat = gfarmGssSendToken(fd, otPtr);
	    gss_release_buffer(&minStat2, otPtr);
	    if (tknStat <= 0) {
		gflog_auth_error(GFARM_MSG_1000619,
		    "gfarmGssInitiateSecurityContext(): "
				 "failed to send response");
		majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_WRITE;
		minStat = GFSL_DEFAULT_MINOR_ERROR;
	    }
	}

	if (GSS_ERROR(majStat)) {
	    break;
	}
    
	if (majStat & GSS_S_CONTINUE_NEEDED) {
	    tknStat = gfarmGssReceiveToken(fd, itPtr,
					   GFARM_GSS_TIMEOUT_INFINITE);
	    if (tknStat <= 0) {
		gflog_auth_error(GFARM_MSG_1000620,
		    "gfarmGssInitiateSecurityContext(): "
				 "failed to receive response");
		majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_READ;
		minStat = GFSL_DEFAULT_MINOR_ERROR;
		break;
	    }
	} else {
	    break;
	}
    }

    if (itPtr->length > 0)
	gss_release_buffer(&minStat2, itPtr);

    if (majStat == GSS_S_COMPLETE && remoteNamePtr != NULL) {
	majStat = gss_inquire_context(&minStat,
				      *scPtr,
				      NULL,
				      remoteNamePtr,
				      NULL,
				      NULL,
				      NULL,
				      NULL,
				      NULL);
    }

    Done:
    if (majStatPtr != NULL)
	*majStatPtr = majStat;
    if (minStatPtr != NULL)
	*minStatPtr = minStat;

    if (majStat != GSS_S_COMPLETE && *scPtr != GSS_C_NO_CONTEXT)
	gss_delete_sec_context(&minStat2, scPtr, GSS_C_NO_BUFFER);

    return majStat == GSS_S_COMPLETE ? 1 : -1;
}
Ejemplo n.º 12
0
/*
 * AEAD wrap API for a single piece of associated data, for compatibility
 * with MIT and as specified by draft-howard-gssapi-aead-00.txt.
 *
 * @ingroup gssapi
 */
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_wrap_aead(OM_uint32 *minor_status,
	      gss_ctx_id_t context_handle,
              int conf_req_flag,
              gss_qop_t qop_req,
              gss_buffer_t input_assoc_buffer,
              gss_buffer_t input_payload_buffer,
              int *conf_state,
              gss_buffer_t output_message_buffer)
{
    OM_uint32 major_status, tmp, flags = 0;
    gss_iov_buffer_desc iov[5];
    size_t i;
    unsigned char *p;

    memset(iov, 0, sizeof(iov));

    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;

    iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
    if (input_assoc_buffer)
	iov[1].buffer = *input_assoc_buffer;

    iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
    if (input_payload_buffer)
	iov[2].buffer.length = input_payload_buffer->length;

    gss_inquire_context(minor_status, context_handle, NULL, NULL,
			NULL, NULL, &flags, NULL, NULL);

    /* krb5 mech rejects padding/trailer if DCE-style is set */
    iov[3].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
					    : GSS_IOV_BUFFER_TYPE_PADDING;
    iov[4].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
					    : GSS_IOV_BUFFER_TYPE_TRAILER;

    major_status = gss_wrap_iov_length(minor_status, context_handle,
				       conf_req_flag, qop_req, conf_state,
				       iov, 5);
    if (GSS_ERROR(major_status))
	return major_status;

    for (i = 0, output_message_buffer->length = 0; i < 5; i++) {
        if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
	    continue;

	output_message_buffer->length += iov[i].buffer.length;
    }

    output_message_buffer->value = malloc(output_message_buffer->length);
    if (output_message_buffer->value == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    for (i = 0, p = output_message_buffer->value; i < 5; i++) {
	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
	    continue;
	else if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
	    memcpy(p, input_payload_buffer->value, input_payload_buffer->length);

	iov[i].buffer.value = p;
	p += iov[i].buffer.length;
    }

    major_status = gss_wrap_iov(minor_status, context_handle, conf_req_flag,
				qop_req, conf_state, iov, 5);
    if (GSS_ERROR(major_status))
        gss_release_buffer(&tmp, output_message_buffer);

    return major_status;
}
Ejemplo n.º 13
0
DWORD
LWIGetGSSSecurityContextInfo(
    gss_ctx_id_t gss_ctx,
    PSTR *pszClientName
    )
{
    DWORD dwError = ERROR_SUCCESS;
    int gss_rc = 0;
    OM_uint32 minor_status = 0;
    gss_name_t src = GSS_C_NO_NAME;
    gss_buffer_desc src_name = GSS_C_EMPTY_BUFFER;
    gss_OID src_type = GSS_C_NULL_OID;

    PSTR pszClient = NULL;

    /* Fetch security context information to make it available
       on the server side (e.g. for security checks) */
    gss_rc = gss_inquire_context(&minor_status,
                                 gss_ctx,
                                 &src,
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL);
    if (gss_rc == GSS_S_COMPLETE) {

        /*
         * Get calling principal name
         */
        gss_rc = gss_display_name(&minor_status, src, &src_name, &src_type);
        if (gss_rc != GSS_S_COMPLETE) {
            /*
             * TODO: error handling
             */

        }

        dwError = EVTStrndup(src_name.value, src_name.length, &pszClient);
        BAIL_ON_EVT_ERROR(dwError);

    } else {
        /* error handling */
    }

    *pszClientName = pszClient;

cleanup:

    gss_release_buffer(&minor_status, &src_name);

    if (src)
    {
        gss_release_name(&minor_status, &src);
    }

    return dwError;

error:
    EVT_SAFE_FREE_STRING(pszClient);
    *pszClientName = NULL;

    goto cleanup;
}
Ejemplo n.º 14
0
int gsscon_authorize (gss_ctx_id_t  inContext, 
                      int          *outAuthorized, 
                      int          *outAuthorizationError)
{
    int err = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0;
    gss_name_t clientName = NULL;
    gss_name_t serviceName = NULL;
    char *clientPrincipal = NULL;
    char *servicePrincipal = NULL;

    if (!inContext            ) { err = EINVAL; }
    if (!outAuthorized        ) { err = EINVAL; }
    if (!outAuthorizationError) { err = EINVAL; }
    
    if (!err) {
        /* Get the client and service principals used to authenticate */
        majorStatus = gss_inquire_context (&minorStatus, 
                                           inContext, 
                                           &clientName, 
                                           &serviceName, 
                                           NULL, NULL, NULL, NULL, NULL);
        if (majorStatus != GSS_S_COMPLETE) { 
            err = minorStatus ? minorStatus : majorStatus; 
        }
    }
    
    if (!err) {
        /* Pull the client principal string out of the gss name */
        gss_buffer_desc nameToken;
        
        majorStatus = gss_display_name (&minorStatus, 
                                        clientName, 
                                        &nameToken, 
                                        NULL);
        if (majorStatus != GSS_S_COMPLETE) { 
            err = minorStatus ? minorStatus : majorStatus; 
        }
        
        if (!err) {
            clientPrincipal = malloc (nameToken.length + 1);
            if (clientPrincipal == NULL) { err = ENOMEM; }
        }
        
        if (!err) {
            memcpy (clientPrincipal, nameToken.value, nameToken.length);
            clientPrincipal[nameToken.length] = '\0';
        }        

        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) {
    //        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); }
    // }
    

	  int authorizationErr = 0;
	  authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);


        
//        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); }
    if (clientPrincipal ) { free (clientPrincipal); }
    if (servicePrincipal) { free (servicePrincipal); }

    return err; 
}
Ejemplo n.º 15
0
/**
 * Initialize GSI Authentication.
 * This method asks the server for authentication.
 * @param sock the socket descriptot
 * @return true on success, false otherwise.
 */
bool GSISocketClient::InitGSIAuthentication(int sock)
{
	OM_uint32                   major_status = 0;
	OM_uint32                   minor_status = 0;
	gss_cred_id_t               credential = GSS_C_NO_CREDENTIAL;
	OM_uint32                   req_flags  = 0;
	OM_uint32                   ret_flags  = 0;
	int                         token_status = 0;
	bool                        return_status = false;
	gss_name_t                  targ_name;
	gss_buffer_desc             name_buffer;
	char                        service[1024];
      
	//acquire our credentials 
	major_status = globus_gss_assist_acquire_cred(&minor_status,
                                                  GSS_C_BOTH,
                                                  &credential);
	if(major_status != GSS_S_COMPLETE) 
	{
		char buf[32];
		std::string msg(FAILED_ACQ_CRED);
		sprintf(buf, "%d", port);
		msg.append(host + ":" + std::string(buf));
		char *gssmsg = NULL;
		globus_gss_assist_display_status_str( &gssmsg,
					    NULL,
					    major_status,
					    minor_status,
					    token_status);
		std::string source(gssmsg);
		free(gssmsg);
		return false;
	}
    	//Request that remote peer authenticate tself
	req_flags = GSS_C_MUTUAL_FLAG;   
	if(_delegate_credentials) 
	{
		req_flags |= GSS_C_DELEG_FLAG; 
	} 
	snprintf(service, sizeof(service), "host@%s", host.c_str());
	//initialize the security context
    	// credential has to be fill in beforehand 
	std::pair<int,int> arg(sock, m_auth_timeout);
	major_status =
        	globus_gss_assist_init_sec_context(&minor_status,
                                           credential,
                                           &gss_context,
                                           _server_contact.empty() ? service :(char*) _server_contact.c_str(), 
                                           req_flags,
                                           &ret_flags,
                                           &token_status,
                                           get_token,
                                           (void *) &arg,
                                           send_token,
                                           (void *) &arg);
	gss_release_cred(&minor_status, &credential);
	if(major_status != GSS_S_COMPLETE)
	{
		char *gssmsg = NULL;
		globus_gss_assist_display_status_str(&gssmsg,
					   NULL,
					   major_status,
					   minor_status,
					   token_status);
		if(gss_context != GSS_C_NO_CONTEXT) 
		{
			gss_delete_sec_context(&minor_status, &gss_context, GSS_C_NO_BUFFER);
		}
		std::string source(gssmsg);
		free(gssmsg);
		return_status = false;		
	}
	else
	{
		major_status = gss_inquire_context(&minor_status,
					 gss_context,
					 NULL,
					 &targ_name,
					 NULL,
					 NULL,
					 NULL,
					 NULL,
					 NULL);
		return_status = (major_status == GSS_S_COMPLETE); 
		major_status = gss_display_name(&minor_status, targ_name, &name_buffer, NULL);
		gss_release_name(&minor_status, &targ_name);
	}
	if (return_status == false && gss_context != GSS_C_NO_CONTEXT) 
	{
		gss_delete_sec_context(&minor_status, &gss_context, GSS_C_NO_BUFFER);
	}
	if (return_status == false) 
	{
		char *gssmsg = NULL;
		globus_gss_assist_display_status_str( &gssmsg,
			NULL,
			major_status,
			minor_status,
			token_status);
		std::string source(gssmsg);
		free(gssmsg);
	}
	return return_status;
}
Ejemplo n.º 16
0
/**
 * @brief Compares two RPC creds
 *
 * @param[in] cred1 First RPC cred
 * @param[in] cred2 Second RPC cred
 *
 * @return true if same, false otherwise
 */
bool nfs_compare_clientcred(nfs_client_cred_t *cred1,
			    nfs_client_cred_t *cred2)
{
#ifdef _HAVE_GSSAPI
	gss_name_t cred1_cred_name;
	gss_name_t cred2_cred_name;
	OM_uint32 maj_stat, min_stat;
	int status;
#endif


	if (cred1 == NULL)
		return false;
	if (cred2 == NULL)
		return false;

	if (cred1->flavor != cred2->flavor)
		return false;

	switch (cred1->flavor) {
	case AUTH_UNIX:
		if (cred1->auth_union.auth_unix.aup_uid !=
		    cred2->auth_union.auth_unix.aup_uid)
			return false;
		if (cred1->auth_union.auth_unix.aup_gid !=
		    cred2->auth_union.auth_unix.aup_gid)
			return false;
		break;

#ifdef _HAVE_GSSAPI
	case RPCSEC_GSS:
		maj_stat = gss_inquire_context(&min_stat,
			cred1->auth_union.auth_gss.gss_context_id,
			&cred1_cred_name, NULL, NULL, NULL, NULL, NULL, NULL);

		if (maj_stat != GSS_S_COMPLETE &&
		    maj_stat != GSS_S_CONTEXT_EXPIRED)
			return false;

		 maj_stat = gss_inquire_context(&min_stat,
			cred2->auth_union.auth_gss.gss_context_id,
			&cred2_cred_name, NULL, NULL, NULL, NULL, NULL, NULL);

		if (maj_stat != GSS_S_COMPLETE &&
		    maj_stat != GSS_S_CONTEXT_EXPIRED)
			return false;

		maj_stat = gss_compare_name(&min_stat, cred1_cred_name,
					    cred2_cred_name, &status);
		if (maj_stat != GSS_S_COMPLETE)
			return false;

		if (status == 0)
			return false;

		break;
#endif

	default:
		if (memcmp
		    (&cred1->auth_union, &cred2->auth_union, cred1->length))
			return false;
		break;
	}

	/* If this point is reached, structures are the same */
	return true;
}
int
GSI_SOCKET_authentication_init(GSI_SOCKET *self, char *accepted_peer_names[])
{
    int				token_status;
    gss_cred_id_t		creds = GSS_C_NO_CREDENTIAL;
    gss_name_t			server_gss_name = GSS_C_NO_NAME;
    OM_uint32			req_flags = 0, ret_flags = 0;
    int				return_value = GSI_SOCKET_ERROR;
    gss_buffer_desc		gss_buffer = { 0 }, tmp_gss_buffer = { 0 };
    gss_name_t			target_name = GSS_C_NO_NAME;
    gss_OID			target_name_type = GSS_C_NO_OID;
    int				i, rc=0, sock;
    FILE			*fp = NULL;
    char                        *cert_dir = NULL;
    globus_result_t res;
    
    if (self == NULL)
    {
	return GSI_SOCKET_ERROR;
    }

    if (accepted_peer_names == NULL ||
	accepted_peer_names[0] == NULL) {
	return GSI_SOCKET_ERROR;
    }

    if (self->gss_context != GSS_C_NO_CONTEXT)
    {
	GSI_SOCKET_set_error_string(self, "GSI_SOCKET already authenticated");
	goto error;
    }

    res = GLOBUS_GSI_SYSCONFIG_GET_CERT_DIR(&cert_dir);
    if (res == GLOBUS_SUCCESS) {
        myproxy_debug("using trusted certificates directory %s", cert_dir);
    } else {
        verror_put_string("error getting trusted certificates directory");
        globus_error_to_verror(res);
        goto error;
    }

    self->major_status = globus_gss_assist_acquire_cred(&self->minor_status,
							GSS_C_INITIATE,
							&creds);

    if (self->major_status != GSS_S_COMPLETE) {
	if (self->allow_anonymous) {
	    req_flags |= GSS_C_ANON_FLAG;
	    myproxy_debug("no valid credentials found -- "
			  "performing anonymous authentication");
	} else {
	    goto error;
	}
    }

    req_flags |= GSS_C_REPLAY_FLAG;
    req_flags |= GSS_C_MUTUAL_FLAG;
    req_flags |= GSS_C_CONF_FLAG;
    req_flags |= GSS_C_INTEG_FLAG;

    if ((sock = dup(self->sock)) < 0) {
	GSI_SOCKET_set_error_string(self, "dup() of socket fd failed");
	self->error_number = errno;
	goto error;
    }
    if ((fp = fdopen(sock, "r")) == NULL) {
	GSI_SOCKET_set_error_string(self, "fdopen() of socket failed");
	self->error_number = errno;
	goto error;
    }
    if (setvbuf(fp, NULL, _IONBF, 0) != 0) {
	GSI_SOCKET_set_error_string(self, "setvbuf() for socket failed");
	self->error_number = errno;
	goto error;
    }
    
    self->major_status =
	globus_gss_assist_init_sec_context(&self->minor_status,
					   creds,
					   &self->gss_context,
					   "GSI-NO-TARGET",
					   req_flags,
					   &ret_flags,
					   &token_status,
					   globus_gss_assist_token_get_fd,
					   (void *)fp,
					   assist_write_token,
					   (void *)&self->sock);

    if (self->major_status != GSS_S_COMPLETE) {
        goto error;
    }

    
    /* Verify that all service requests were honored. */
    req_flags &= ~(GSS_C_ANON_FLAG); /* GSI GSSAPI doesn't set this flag */
    if ((req_flags & ret_flags) != req_flags) {
      GSI_SOCKET_set_error_string(self,
                                  "requested GSSAPI service not supported");
      goto error;
    }

    if (ret_flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG) {
        self->limited_proxy = 1;
    }

    /* Check the authenticated identity of the server. */
    self->major_status = gss_inquire_context(&self->minor_status,
					     self->gss_context,
					     NULL,
					     &server_gss_name,
					     NULL, NULL, NULL, NULL, NULL);
    if (self->major_status != GSS_S_COMPLETE) {
	GSI_SOCKET_set_error_string(self, "gss_inquire_context() failed");
	goto error;
    }

    self->major_status = gss_display_name(&self->minor_status,
					  server_gss_name, &gss_buffer, NULL);
    if (self->major_status != GSS_S_COMPLETE) {
	GSI_SOCKET_set_error_string(self, "gss_display_name() failed");
	goto error;
    }

    self->peer_name = strdup(gss_buffer.value);
    myproxy_debug("server name: %s", self->peer_name);
    myproxy_debug("checking that server name is acceptable...");

    /* We told gss_assist_init_sec_context() not to check the server
       name so we can check it manually here. */
    for (i=0; accepted_peer_names[i] != NULL; i++) {
	tmp_gss_buffer.value = (void *)accepted_peer_names[i];
	tmp_gss_buffer.length = strlen(accepted_peer_names[i]);
	if (strchr(accepted_peer_names[i],'@') && 
	    !strstr(accepted_peer_names[i],"CN=")) { 
	    target_name_type = GSS_C_NT_HOSTBASED_SERVICE;
	} else {
	    target_name_type = GSS_C_NO_OID;
	}
	self->major_status = gss_import_name(&self->minor_status,
					     &tmp_gss_buffer,
					     target_name_type,
					     &target_name);
	if (self->major_status != GSS_S_COMPLETE) {
	    char error_string[550];
	    sprintf(error_string, "failed to import GSS name \"%.500s\"",
		    accepted_peer_names[i]);
	    GSI_SOCKET_set_error_string(self, error_string);
	    goto error;
	}
	self->major_status = gss_compare_name(&self->minor_status,
					      server_gss_name,
					      target_name, &rc);
        gss_release_name(&self->minor_status, &target_name);
	if (self->major_status != GSS_S_COMPLETE) {
	    char error_string[1050];
	    sprintf(error_string,
		    "gss_compare_name(\"%.500s\",\"%.500s\") failed",
		    self->peer_name, accepted_peer_names[i]);
	    GSI_SOCKET_set_error_string(self, error_string);
	    goto error;
	}

	if (rc) {
	    myproxy_debug("server name matches \"%s\"",
                      accepted_peer_names[i]);
	    break;
	} else {
	    myproxy_debug("server name does not match \"%s\"",
                      accepted_peer_names[i]);
	}
    }
    if (!rc) {		/* no match with acceptable target names */
	GSI_SOCKET_set_error_string(self, "authenticated peer name does not match");
	return_value = GSI_SOCKET_UNAUTHORIZED;
	goto error;
    }
    myproxy_debug("authenticated server name is acceptable");

    /* Success */
    return_value = GSI_SOCKET_SUCCESS;
    
  error:
    {
	OM_uint32 minor_status;
	gss_release_cred(&minor_status, &creds);
	gss_release_buffer(&minor_status, &gss_buffer);
	gss_release_name(&minor_status, &server_gss_name);
    }
    if (cert_dir) free(cert_dir);
    if (fp) fclose(fp);
    
    return return_value;
}
Ejemplo n.º 18
0
static int
check_iprop_rpcsec_auth(struct svc_req *rqstp)
{
    /* XXX Since the client can authenticate against any principal in
       the database, we need to do a sanity check.  Only checking for
       "kiprop" now, but that means theoretically the client could be
       authenticating to kiprop on some other machine.  */
    /* Code taken from kadm_rpc_svc.c, tweaked.  */

     gss_ctx_id_t ctx;
     krb5_context kctx;
     OM_uint32 maj_stat, min_stat;
     gss_name_t name;
     krb5_principal princ;
     int ret, success;
     krb5_data *c1, *c2, *realm;
     gss_buffer_desc gss_str;
     kadm5_server_handle_t handle;
     size_t slen;
     char *sdots;

     success = 0;
     handle = (kadm5_server_handle_t)global_server_handle;

     if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS)
	  return 0;

     ctx = rqstp->rq_svccred;

     maj_stat = gss_inquire_context(&min_stat, ctx, NULL, &name,
				    NULL, NULL, NULL, NULL, NULL);
     if (maj_stat != GSS_S_COMPLETE) {
	  krb5_klog_syslog(LOG_ERR, "check_rpcsec_auth: "
			   "failed inquire_context, stat=%u", maj_stat);
	  log_badauth(maj_stat, min_stat,
		      &rqstp->rq_xprt->xp_raddr, NULL);
	  goto fail_name;
     }

     kctx = handle->context;
     ret = gss_to_krb5_name_1(rqstp, kctx, name, &princ, &gss_str);
     if (ret == 0)
	  goto fail_name;

     slen = gss_str.length;
     trunc_name(&slen, &sdots);
     /*
      * Since we accept with GSS_C_NO_NAME, the client can authenticate
      * against the entire kdb.  Therefore, ensure that the service
      * name is something reasonable.
      */
     if (krb5_princ_size(kctx, princ) != 2)
	  goto fail_princ;

     c1 = krb5_princ_component(kctx, princ, 0);
     c2 = krb5_princ_component(kctx, princ, 1);
     realm = krb5_princ_realm(kctx, princ);
     if (strncmp(handle->params.realm, realm->data, realm->length) == 0
	 && strncmp("kiprop", c1->data, c1->length) == 0) {
	 success = 1;
     }

fail_princ:
     if (!success) {
	 krb5_klog_syslog(LOG_ERR, "bad service principal %.*s%s",
			  (int) slen, (char *) gss_str.value, sdots);
     }
     gss_release_buffer(&min_stat, &gss_str);
     krb5_free_principal(kctx, princ);
fail_name:
     gss_release_name(&min_stat, &name);
     return success;
}
Ejemplo n.º 19
0
static int
gss_auth(void *app_data, char *host)
{

    OM_uint32 maj_stat, min_stat;
    gss_name_t target_name;
    gss_buffer_desc input, output_token;
    int context_established = 0;
    char *p;
    int n;
    gss_channel_bindings_t bindings;
    struct gssapi_data *d = app_data;
    OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;

    const char *knames[] = { "ftp", "host", NULL }, **kname = knames;


    if(import_name(*kname++, host, &target_name))
	return AUTH_ERROR;

    input.length = 0;
    input.value = NULL;

    if (ftp_do_gss_bindings) {
	bindings = malloc(sizeof(*bindings));
	if (bindings == NULL)
	    errx(1, "out of memory");

	sockaddr_to_gss_address (myctladdr,
				 &bindings->initiator_addrtype,
				 &bindings->initiator_address);
	sockaddr_to_gss_address (hisctladdr,
				 &bindings->acceptor_addrtype,
				 &bindings->acceptor_address);

	bindings->application_data.length = 0;
	bindings->application_data.value = NULL;
    } else
	bindings = GSS_C_NO_CHANNEL_BINDINGS;

    if (ftp_do_gss_delegate)
	mech_flags |= GSS_C_DELEG_FLAG;

    while(!context_established) {
	maj_stat = gss_init_sec_context(&min_stat,
					GSS_C_NO_CREDENTIAL,
					&d->context_hdl,
					target_name,
					GSS_C_NO_OID,
                                        mech_flags,
					0,
					bindings,
					&input,
					NULL,
					&output_token,
					NULL,
					NULL);
	if (GSS_ERROR(maj_stat)) {
	    OM_uint32 new_stat;
	    OM_uint32 msg_ctx = 0;
	    gss_buffer_desc status_string;

	    d->context_hdl = GSS_C_NO_CONTEXT;

	    gss_release_name(&min_stat, &target_name);

	    if(*kname != NULL) {

		if(import_name(*kname++, host, &target_name)) {
		    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
			free(bindings);
		    return AUTH_ERROR;
		}
		continue;
	    }

	    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		free(bindings);

	    gss_display_status(&new_stat,
			       min_stat,
			       GSS_C_MECH_CODE,
			       GSS_C_NO_OID,
			       &msg_ctx,
			       &status_string);
	    printf("Error initializing security context: %.*s\n",
		   (int)status_string.length,
		   (char*)status_string.value);
	    gss_release_buffer(&new_stat, &status_string);
	    return AUTH_CONTINUE;
	}

	if (input.value) {
	    free(input.value);
	    input.value = NULL;
	    input.length = 0;
	}
	if (output_token.length != 0) {
	    base64_encode(output_token.value, output_token.length, &p);
	    gss_release_buffer(&min_stat, &output_token);
	    n = command("ADAT %s", p);
	    free(p);
	}
	if (GSS_ERROR(maj_stat)) {
	    if (d->context_hdl != GSS_C_NO_CONTEXT)
		gss_delete_sec_context (&min_stat,
					&d->context_hdl,
					GSS_C_NO_BUFFER);
	    break;
	}
	if (maj_stat & GSS_S_CONTINUE_NEEDED) {
	    p = strstr(reply_string, "ADAT=");
	    if(p == NULL){
		printf("Error: expected ADAT in reply. got: %s\n",
		       reply_string);
		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		    free(bindings);
		return AUTH_ERROR;
	    } else {
		p+=5;
		input.value = malloc(strlen(p));
		input.length = base64_decode(p, input.value);
	    }
	} else {
	    if(code != 235) {
		printf("Unrecognized response code: %d\n", code);
		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		    free(bindings);
		return AUTH_ERROR;
	    }
	    context_established = 1;
	}
    }

    gss_release_name(&min_stat, &target_name);

    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
	free(bindings);
    if (input.value)
	free(input.value);

    {
	gss_name_t targ_name;

	maj_stat = gss_inquire_context(&min_stat,
				       d->context_hdl,
				       NULL,
				       &targ_name,
				       NULL,
				       NULL,
				       NULL,
				       NULL,
				       NULL);
	if (GSS_ERROR(maj_stat) == 0) {
	    gss_buffer_desc name;
	    maj_stat = gss_display_name (&min_stat,
					 targ_name,
					 &name,
					 NULL);
	    if (GSS_ERROR(maj_stat) == 0) {
		printf("Authenticated to <%.*s>\n",
			(int)name.length,
			(char *)name.value);
		gss_release_buffer(&min_stat, &name);
	    }
	    gss_release_name(&min_stat, &targ_name);
	} else
	    printf("Failed to get gss name of peer.\n");
    }


    return AUTH_OK;
}
Ejemplo n.º 20
0
OM_uint32 gssi_inquire_context(OM_uint32 *minor_status,
                              gss_ctx_id_t context_handle,
                              gss_name_t *src_name,
                              gss_name_t *targ_name,
                              OM_uint32 *lifetime_rec,
                              gss_OID *mech_type,
                              OM_uint32 *ctx_flags,
                              int *locally_initiated,
                              int *open)
{
    struct gpp_context_handle *ctx_handle;
    struct gpp_name_handle *s_name = NULL;
    struct gpp_name_handle *t_name = NULL;
    gss_OID mech_oid;
    OM_uint32 maj, min;

    GSSI_TRACE();

    if (!context_handle) {
        return GSS_S_CALL_INACCESSIBLE_READ;
    }

    ctx_handle = (struct gpp_context_handle *)context_handle;
    if (!ctx_handle->local &&
        !ctx_handle->remote) {
        return GSS_S_CALL_INACCESSIBLE_READ;
    }

    if (src_name) {
        s_name = calloc(1, sizeof(struct gpp_name_handle));
        if (!s_name) {
            min = ENOMEM;
            maj = GSS_S_FAILURE;
            goto done;
        }
    }
    if (targ_name) {
        t_name = calloc(1, sizeof(struct gpp_name_handle));
        if (!t_name) {
            min = ENOMEM;
            maj = GSS_S_FAILURE;
            goto done;
        }
    }

    if (ctx_handle->local) {
        maj = gss_inquire_context(&min,
                                  ctx_handle->local,
                                  s_name ? &s_name->local : NULL,
                                  t_name ? &t_name->local : NULL,
                                  lifetime_rec,
                                  &mech_oid,
                                  ctx_flags,
                                  locally_initiated,
                                  open);
    } else {
        maj = gpm_inquire_context(&min,
                                  ctx_handle->remote,
                                  s_name ? &s_name->remote : NULL,
                                  t_name ? &t_name->remote : NULL,
                                  lifetime_rec,
                                  &mech_oid,
                                  ctx_flags,
                                  locally_initiated,
                                  open);
    }

    if (maj != GSS_S_COMPLETE) {
        goto done;
    }

    if (s_name) {
        maj = gpp_copy_oid(&min, mech_oid, &s_name->mech_type);
        if (maj != GSS_S_COMPLETE) {
            goto done;
        }
    }

    if (t_name) {
        maj = gpp_copy_oid(&min, mech_oid, &t_name->mech_type);
        if (maj != GSS_S_COMPLETE) {
            goto done;
        }
    }

done:
    *minor_status = gpp_map_error(min);
    if (maj == GSS_S_COMPLETE) {
        if (mech_type) {
            *mech_type = mech_oid;
        } else {
            (void)gss_release_oid(&min, &mech_oid);
        }
        if (src_name) {
            *src_name = (gss_name_t)s_name;
        }
        if (targ_name) {
            *targ_name = (gss_name_t)t_name;
        }
    } else {
        (void)gss_release_oid(&min, &mech_oid);
        (void)gssi_release_name(&min, (gss_name_t *)&s_name);
        (void)gssi_release_name(&min, (gss_name_t *)&t_name);
    }
    return maj;
}
Ejemplo n.º 21
0
gss_client_response *authenticate_gss_server_step(gss_server_state *state, const char *auth_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;
    gss_client_response *response = NULL;
    
    // Always clear out the old response
    if (state->response != NULL)
    {
        free(state->response);
        state->response = NULL;
    }
    
    // we don't need to check the authentication token if S4U2Self protocol
    // transition was done, because we already have the client credentials.
    if (state->client_creds == GSS_C_NO_CREDENTIAL)
    {
	if (auth_data && *auth_data)
	{
	    int len;
	    input_token.value = base64_decode(auth_data, &len);
	    input_token.length = len;
	}
	else
	{
	    response = calloc(1, sizeof(gss_client_response));
	    if(response == NULL) die1("Memory allocation failed");
	    response->message = strdup("No auth_data value in request from client");
	    response->return_code = 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))
	{
	    response = gss_error(__func__, "gss_accept_sec_context", maj_stat, min_stat);
	    response->return_code = 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))
    {
	response = gss_error(__func__, "gss_display_name", maj_stat, min_stat);
	response->return_code = 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))
	{
	    response = gss_error(__func__, "gss_inquire_context", maj_stat, min_stat);
	    response->return_code = AUTH_GSS_ERROR;
	    goto end;
	}
	maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL);
	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_display_name", maj_stat, min_stat);
	    response->return_code = 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;
    }

    if (state->constrained_delegation && state->client_creds != GSS_C_NO_CREDENTIAL)
    {
	if ((response = store_gss_creds(state)) != NULL)
	{
	    goto end;
	}
    }

    ret = AUTH_GSS_COMPLETE;
    
end:
    if (output_token.length)
        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));
      if(response == NULL) die1("Memory allocation failed");
      response->return_code = ret;
    }

    // Return the response
    return response;
}
Ejemplo n.º 22
0
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                      struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  curl_socket_t sock = conn->sock[sockindex];
  CURLcode code;
  ssize_t actualread;
  ssize_t written;
  int result;
  OM_uint32 gss_major_status, gss_minor_status, gss_status;
  OM_uint32 gss_ret_flags;
  int gss_conf_state, gss_enc;
  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
  gss_name_t       server = GSS_C_NO_NAME;
  gss_name_t       gss_client_name = GSS_C_NO_NAME;
  unsigned short   us_length;
  char             *user=NULL;
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];

  /*   GSSAPI request looks like
   * +----+------+-----+----------------+
   * |VER | MTYP | LEN |     TOKEN      |
   * +----+------+----------------------+
   * | 1  |  1   |  2  | up to 2^16 - 1 |
   * +----+------+-----+----------------+
   */

  /* prepare service name */
  if(strchr(serviceptr,'/')) {
    service.value = malloc(strlen(serviceptr));
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr);
    memcpy(service.value, serviceptr, service.length);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       (gss_OID) GSS_C_NULL_OID, &server);
  }
  else {
    service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
    snprintf(service.value, service.length+1, "%s@%s",
             serviceptr, conn->proxy.name);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       gss_nt_service_name, &server);
  }

  gss_release_buffer(&gss_status, &service); /* clear allocated memory */

  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_import_name()")) {
    failf(data, "Failed to create service name.");
    gss_release_name(&gss_status, &server);
    return CURLE_COULDNT_CONNECT;
  }

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    gss_major_status = Curl_gss_init_sec_context(data,
                                                 &gss_minor_status,
                                                 &gss_context,
                                                 server,
                                                 NULL,
                                                 gss_token,
                                                 &gss_send_token,
                                                 &gss_ret_flags);

    if(gss_token != GSS_C_NO_BUFFER)
      gss_release_buffer(&gss_status, &gss_recv_token);
    if(check_gss_err(data,gss_major_status,
                     gss_minor_status,"gss_init_sec_context")) {
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to initial GSSAPI token.");
      return CURLE_COULDNT_CONNECT;
    }

    if(gss_send_token.length != 0) {
      socksreq[0] = 1;    /* gssapi subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)gss_send_token.length);
      memcpy(socksreq+2,&us_length,sizeof(short));

      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
      if((code != CURLE_OK) || (4 != written)) {
        failf(data, "Failed to send GSSAPI authentication request.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
                              gss_send_token.length, &written);

      if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
        failf(data, "Failed to send GSSAPI authentication token.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

    }

    gss_release_buffer(&gss_status, &gss_send_token);
    gss_release_buffer(&gss_status, &gss_recv_token);
    if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;

    /* analyse response */

    /*   GSSAPI response looks like
     * +----+------+-----+----------------+
     * |VER | MTYP | LEN |     TOKEN      |
     * +----+------+----------------------+
     * | 1  |  1   |  2  | up to 2^16 - 1 |
     * +----+------+-----+----------------+
     */

    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
    if(result != CURLE_OK || actualread != 4) {
      failf(data, "Failed to receive GSSAPI authentication response.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    /* ignore the first (VER) byte */
    if(socksreq[1] == 255) { /* status / message type */
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    if(socksreq[1] != 1) { /* status / messgae type */
      failf(data, "Invalid GSSAPI authentication response type (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(&us_length, socksreq+2, sizeof(short));
    us_length = ntohs(us_length);

    gss_recv_token.length=us_length;
    gss_recv_token.value=malloc(us_length);
    if(!gss_recv_token.value) {
      failf(data,
            "Could not allocate memory for GSSAPI authentication "
            "response token.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }

    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                              gss_recv_token.length, &actualread);

    if(result != CURLE_OK || actualread != us_length) {
      failf(data, "Failed to receive GSSAPI authentication token.");
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    gss_token = &gss_recv_token;
  }

  gss_release_name(&gss_status, &server);

  /* Everything is good so far, user was authenticated! */
  gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
                                          &gss_client_name, NULL, NULL, NULL,
                                          NULL, NULL, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_inquire_context")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
                                      &gss_send_token, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_display_name")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  user=malloc(gss_send_token.length+1);
  if(!user) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    return CURLE_OUT_OF_MEMORY;
  }

  memcpy(user, gss_send_token.value, gss_send_token.length);
  user[gss_send_token.length] = '\0';
  gss_release_name(&gss_status, &gss_client_name);
  gss_release_buffer(&gss_status, &gss_send_token);
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
  free(user);
  user=NULL;

  /* Do encryption */
  socksreq[0] = 1;    /* gssapi subnegotiation version */
  socksreq[1] = 2;    /* encryption message type */

  gss_enc = 0; /* no data protection */
  /* do confidentiality protection if supported */
  if(gss_ret_flags & GSS_C_CONF_FLAG)
    gss_enc = 2;
  /* else do integrity protection */
  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
    gss_enc = 1;

  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
  /* force for the moment to no data protection */
  gss_enc = 0;
  /*
   * Sending the encryption type in clear seems wrong. It should be
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
   * The NEC reference implementations on which this is based is
   * therefore at fault
   *
   *  +------+------+------+.......................+
   *  + ver  | mtyp | len  |   token               |
   *  +------+------+------+.......................+
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
   *  +------+------+------+.......................+
   *
   *   Where:
   *
   *  - "ver" is the protocol version number, here 1 to represent the
   *    first version of the SOCKS/GSS-API protocol
   *
   *  - "mtyp" is the message type, here 2 to represent a protection
   *    -level negotiation message
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */
  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }
  else {
    gss_send_token.length = 1;
    gss_send_token.value = malloc(1);
    if(!gss_send_token.value) {
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }
    memcpy(gss_send_token.value, &gss_enc, 1);

    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
                                GSS_C_QOP_DEFAULT, &gss_send_token,
                                &gss_conf_state, &gss_w_token);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to wrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_send_token);

    us_length = htons((short)gss_w_token.length);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }

  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
  if((code != CURLE_OK) || (4 != written)) {
    failf(data, "Failed to send GSSAPI encryption request.");
    gss_release_buffer(&gss_status, &gss_w_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(data->set.socks5_gssapi_nec) {
    memcpy(socksreq, &gss_enc, 1);
    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
    if((code != CURLE_OK) || ( 1 != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
  }
  else {
    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
                            gss_w_token.length, &written);
    if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_w_token);
  }

  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
  if(result != CURLE_OK || actualread != 4) {
    failf(data, "Failed to receive GSSAPI encryption response.");
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  /* ignore the first (VER) byte */
  if(socksreq[1] == 255) { /* status / message type */
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(socksreq[1] != 2) { /* status / messgae type */
    failf(data, "Invalid GSSAPI encryption response type (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  memcpy(&us_length, socksreq+2, sizeof(short));
  us_length = ntohs(us_length);

  gss_recv_token.length= us_length;
  gss_recv_token.value=malloc(gss_recv_token.length);
  if(!gss_recv_token.value) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_OUT_OF_MEMORY;
  }
  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                            gss_recv_token.length, &actualread);

  if(result != CURLE_OK || actualread != us_length) {
    failf(data, "Failed to receive GSSAPI encryptrion type.");
    gss_release_buffer(&gss_status, &gss_recv_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(!data->set.socks5_gssapi_nec) {
    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
                                  &gss_recv_token, &gss_w_token,
                                  0, GSS_C_QOP_DEFAULT);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to unwrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_recv_token);

    if(gss_w_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_w_token.length);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_w_token.value,gss_w_token.length);
    gss_release_buffer(&gss_status, &gss_w_token);
  }
  else {
    if(gss_recv_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_recv_token.length);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
    gss_release_buffer(&gss_status, &gss_recv_token);
  }

  infof(data, "SOCKS5 access with%s protection granted.\n",
        (socksreq[0]==0)?"out gssapi data":
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));

  conn->socks5_gssapi_enctype = socksreq[0];
  if(socksreq[0] == 0)
    gss_delete_sec_context(&gss_status, &gss_context, NULL);

  return CURLE_OK;
}
Ejemplo n.º 23
0
int
main(int argc, char **argv)
{
    struct http_req req;
    const char *host, *page;
    int i, done, print_body, gssapi_done, gssapi_started;
    char *headers[10]; /* XXX */
    int num_headers;
    gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
    gss_name_t server = GSS_C_NO_NAME;
    int optind = 0;
    gss_OID mech_oid;
    OM_uint32 flags;

    setprogname(argv[0]);

    if(getarg(http_args, num_http_args, argc, argv, &optind))
	usage(1);

    if (help_flag)
	usage (0);

    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optind;
    argv += optind;

    mech_oid = select_mech(mech);

    if (argc != 1 && argc != 2)
	errx(1, "usage: %s host [page]", getprogname());
    host = argv[0];
    if (argc == 2)
	page = argv[1];
    else
	page = "/";

    flags = 0;
    if (delegate_flag)
	flags |= GSS_C_DELEG_FLAG;
    if (mutual_flag)
	flags |= GSS_C_MUTUAL_FLAG;

    done = 0;
    num_headers = 0;
    gssapi_done = 1;
    gssapi_started = 0;
    do {
	print_body = 0;

	http_query(host, page, headers, num_headers, &req);
	for (i = 0 ; i < num_headers; i++)
	    free(headers[i]);
	num_headers = 0;

	if (strstr(req.response, " 200 ") != NULL) {
	    print_body = 1;
	    done = 1;
	} else if (strstr(req.response, " 401 ") != NULL) {
	    if (http_find_header(&req, "WWW-Authenticate:") == NULL)
		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
	    gssapi_done = 0;
	}

	if (!gssapi_done) {
	    const char *h = http_find_header(&req, "WWW-Authenticate:");
	    if (h == NULL)
		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);

	    if (strncasecmp(h, "Negotiate", 9) == 0) {
		OM_uint32 maj_stat, min_stat;
		gss_buffer_desc input_token, output_token;

		if (verbose_flag)
		    printf("Negotiate found\n");

		if (server == GSS_C_NO_NAME) {
		    char *name;
		    asprintf(&name, "%s@%s", gss_service, host);
		    input_token.length = strlen(name);
		    input_token.value = name;

		    maj_stat = gss_import_name(&min_stat,
					       &input_token,
					       GSS_C_NT_HOSTBASED_SERVICE,
					       &server);
		    if (GSS_ERROR(maj_stat))
			gss_err (1, min_stat, "gss_inport_name");
		    free(name);
		    input_token.length = 0;
		    input_token.value = NULL;
		}

		i = 9;
		while(h[i] && isspace((unsigned char)h[i]))
		    i++;
		if (h[i] != '\0') {
		    int len = strlen(&h[i]);
		    if (len == 0)
			errx(1, "invalid Negotiate token");
		    input_token.value = emalloc(len);
		    len = base64_decode(&h[i], input_token.value);
		    if (len < 0)
			errx(1, "invalid base64 Negotiate token %s", &h[i]);
		    input_token.length = len;
		} else {
		    if (gssapi_started)
			errx(1, "Negotiate already started");
		    gssapi_started = 1;

		    input_token.length = 0;
		    input_token.value = NULL;
		}

		maj_stat =
		    gss_init_sec_context(&min_stat,
					 GSS_C_NO_CREDENTIAL,
					 &context_hdl,
					 server,
					 mech_oid,
					 flags,
					 0,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &input_token,
					 NULL,
					 &output_token,
					 NULL,
					 NULL);
		if (GSS_ERROR(maj_stat))
		    gss_err (1, min_stat, "gss_init_sec_context");
		else if (maj_stat & GSS_S_CONTINUE_NEEDED)
		    gssapi_done = 0;
		else {
		    gss_name_t targ_name, src_name;
		    gss_buffer_desc name_buffer;
		    gss_OID mech_type;

		    gssapi_done = 1;

		    printf("Negotiate done: %s\n", mech);

		    maj_stat = gss_inquire_context(&min_stat,
						   context_hdl,
						   &src_name,
						   &targ_name,
						   NULL,
						   &mech_type,
						   NULL,
						   NULL,
						   NULL);
		    if (GSS_ERROR(maj_stat))
			gss_err (1, min_stat, "gss_inquire_context");

		    maj_stat = gss_display_name(&min_stat,
						src_name,
						&name_buffer,
						NULL);
		    if (GSS_ERROR(maj_stat))
			gss_err (1, min_stat, "gss_display_name");

		    printf("Source: %.*s\n",
			   (int)name_buffer.length,
			   (char *)name_buffer.value);

		    gss_release_buffer(&min_stat, &name_buffer);

		    maj_stat = gss_display_name(&min_stat,
						targ_name,
						&name_buffer,
						NULL);
		    if (GSS_ERROR(maj_stat))
			gss_err (1, min_stat, "gss_display_name");

		    printf("Target: %.*s\n",
			   (int)name_buffer.length,
			   (char *)name_buffer.value);

		    gss_release_name(&min_stat, &targ_name);
		    gss_release_buffer(&min_stat, &name_buffer);
		}

		if (output_token.length) {
		    char *neg_token;

		    base64_encode(output_token.value,
				  output_token.length,
				  &neg_token);

		    asprintf(&headers[0], "Authorization: Negotiate %s",
			     neg_token);

		    num_headers = 1;
		    free(neg_token);
		    gss_release_buffer(&min_stat, &output_token);
		}
		if (input_token.length)
		    free(input_token.value);

	    } else
		done = 1;
	} else
	    done = 1;

	if (verbose_flag) {
	    printf("%s\n\n", req.response);

	    for (i = 0; i < req.num_headers; i++)
		printf("%s\n", req.headers[i]);
	    printf("\n");
	}
	if (print_body || verbose_flag)
	    printf("%.*s\n", (int)req.body_size, (char *)req.body);

	http_req_free(&req);
    } while (!done);

    if (gssapi_done == 0)
	errx(1, "gssapi not done but http dance done");

    return 0;
}
Ejemplo n.º 24
0
uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type, gss_OID mech,
                                  gss_ctx_id_t *in, gssx_ctx *out)
{
    uint32_t ret_maj;
    uint32_t ret_min;
    gss_name_t src_name = GSS_C_NO_NAME;
    gss_name_t targ_name = GSS_C_NO_NAME;
    gss_buffer_desc export_buffer = GSS_C_EMPTY_BUFFER;
    gss_krb5_lucid_context_v1_t *lucid = NULL;
    uint32_t lifetime_rec;
    gss_OID mech_type;
    uint32_t ctx_flags;
    int is_locally_initiated;
    int is_open;
    int ret;

    /* we do not need the client to release anything until we handle state */
    out->needs_release = false;

    ret_maj = gss_inquire_context(&ret_min, *in, &src_name, &targ_name,
                                  &lifetime_rec, &mech_type, &ctx_flags,
                                  &is_locally_initiated, &is_open);
    if (ret_maj) {
        if (type == EXP_CTX_PARTIAL) {
            /* This may happen on partially established context,
             * so just go on and put in what we can */
            goto export;
        }
        goto done;
    }

    ret = gp_conv_oid_to_gssx(mech_type, &out->mech);
    if (ret) {
        ret_maj = GSS_S_FAILURE;
        ret_min = ret;
        goto done;
    }

    ret_maj = gp_conv_name_to_gssx(&ret_min, src_name, &out->src_name);
    if (ret_maj) {
        goto done;
    }

    ret_maj = gp_conv_name_to_gssx(&ret_min, targ_name, &out->targ_name);
    if (ret_maj) {
        goto done;
    }

    out->lifetime = lifetime_rec;

    out->ctx_flags = ctx_flags;

    if (is_locally_initiated) {
        out->locally_initiated = true;
    }

    if (is_open) {
        out->open = true;
    }

export:
    /* note: once converted the original context token is not usable anymore,
     * so this must be the last call to use it */
    switch (type) {
Ejemplo n.º 25
0
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)
    {
        size_t 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;
    }
    
    Py_BEGIN_ALLOW_THREADS
    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,
                                      (OM_uint32 *)&state->gss_flags,
                                      NULL,
                                      &state->client_creds);
    Py_END_ALLOW_THREADS
    
    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;
}
Ejemplo n.º 26
0
OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_context (
            OM_uint32 * minor_status,
            gss_const_ctx_id_t context_handle,
            gss_name_t * src_name,
            gss_name_t * targ_name,
            OM_uint32 * lifetime_rec,
            gss_OID * mech_type,
            OM_uint32 * ctx_flags,
            int * locally_initiated,
            int * open_context
           )
{
    gssspnego_ctx ctx;
    OM_uint32 maj_stat, junk;
    gss_name_t src_mn, targ_mn;

    *minor_status = 0;

    if (context_handle == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;

    ctx = (gssspnego_ctx)context_handle;

    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;

    maj_stat = gss_inquire_context(minor_status,
				   ctx->negotiated_ctx_id,
				   &src_mn,
				   &targ_mn,
				   lifetime_rec,
				   mech_type,
				   ctx_flags,
				   locally_initiated,
				   open_context);
    if (maj_stat != GSS_S_COMPLETE)
	return maj_stat;

    if (src_name) {
	spnego_name name = calloc(1, sizeof(*name));
	if (name == NULL)
	    goto enomem;
	name->mech = src_mn;
	*src_name = (gss_name_t)name;
    } else
	gss_release_name(&junk, &src_mn);

    if (targ_name) {
	spnego_name name = calloc(1, sizeof(*name));
	if (name == NULL) {
	    gss_release_name(minor_status, src_name);
	    goto enomem;
	}
	name->mech = targ_mn;
	*targ_name = (gss_name_t)name;
    } else
	gss_release_name(&junk, &targ_mn);

    return GSS_S_COMPLETE;

enomem:
    gss_release_name(&junk, &targ_mn);
    gss_release_name(&junk, &src_mn);
    *minor_status = ENOMEM;
    return GSS_S_FAILURE;
}
Ejemplo n.º 27
0
/*
 * Curl_sasl_create_gssapi_security_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) security
 * token message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - Pointer to the optional base64 encoded challenge message.
 * krb5    [in/out] - The gssapi data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                                                  const char *chlg64,
                                                  struct kerberos5data *krb5,
                                                  char **outptr,
                                                  size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  size_t messagelen = 0;
  unsigned char *chlg = NULL;
  unsigned char *message = NULL;
  OM_uint32 gss_status;
  OM_uint32 gss_major_status;
  OM_uint32 gss_minor_status;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  unsigned int indata = 0;
  unsigned int outdata = 0;
  gss_qop_t qop = GSS_C_QOP_DEFAULT;
  unsigned int sec_layer = 0;
  unsigned int max_size = 0;
  gss_name_t username = GSS_C_NO_NAME;
  gss_buffer_desc username_token;

  /* Decode the base-64 encoded input message */
  if(strlen(chlg64) && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!chlg) {
    infof(data, "GSSAPI handshake failure (empty security message)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Get the fully qualified username back from the context */
  gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context,
                                         &username, NULL, NULL, NULL, NULL,
                                         NULL, NULL);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, gss_minor_status,
                       "gss_inquire_context() failed: ");

    Curl_safefree(chlg);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Convert the username from internal format to a displayable token */
  gss_major_status = gss_display_name(&gss_minor_status, username,
                                      &username_token, NULL);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: ");

    Curl_safefree(chlg);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Setup the challenge "input" security buffer */
  input_token.value = chlg;
  input_token.length = chlglen;

  /* Decrypt the inbound challenge and obtain the qop */
  gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token,
                                &output_token, NULL, &qop);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: ");

    gss_release_buffer(&gss_status, &username_token);
    Curl_safefree(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
  if(output_token.length != 4) {
    infof(data, "GSSAPI handshake failure (invalid security data)\n");

    gss_release_buffer(&gss_status, &username_token);
    Curl_safefree(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Copy the data out and free the challenge as it is not required anymore */
  memcpy(&indata, output_token.value, 4);
  gss_release_buffer(&gss_status, &output_token);
  Curl_safefree(chlg);

  /* Extract the security layer */
  sec_layer = indata & 0x000000FF;
  if(!(sec_layer & GSSAUTH_P_NONE)) {
    infof(data, "GSSAPI handshake failure (invalid security layer)\n");

    gss_release_buffer(&gss_status, &username_token);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Extract the maximum message size the server can receive */
  max_size = ntohl(indata & 0xFFFFFF00);
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we don't require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate our message */
  messagelen = sizeof(outdata) + username_token.length + 1;
  message = malloc(messagelen);
  if(!message) {
    gss_release_buffer(&gss_status, &username_token);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Populate the message with the security layer, client supported receive
     message size and authorization identity including the 0x00 based
     terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization
     identity is not terminated with the zero-valued (%x00) octet." it seems
     necessary to include it. */
  outdata = htonl(max_size) | sec_layer;
  memcpy(message, &outdata, sizeof(outdata));
  memcpy(message + sizeof(outdata), username_token.value,
         username_token.length);
  message[messagelen - 1] = '\0';

  /* Free the username token as it is not required anymore */
  gss_release_buffer(&gss_status, &username_token);

  /* Setup the "authentication data" security buffer */
  input_token.value = message;
  input_token.length = messagelen;

  /* Encrypt the data */
  gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0,
                              GSS_C_QOP_DEFAULT, &input_token, NULL,
                              &output_token);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: ");

    Curl_safefree(message);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Base64 encode the response */
  result = Curl_base64_encode(data, (char *) output_token.value,
                              output_token.length, outptr, outlen);

  /* Free the output buffer */
  gss_release_buffer(&gss_status, &output_token);

  /* Free the message buffer */
  Curl_safefree(message);

  return result;
}
Ejemplo n.º 28
0
int
main(int argc, char **argv)
{
    int i, s, done, print_body, gssapi_done, gssapi_started, optidx = 0;
    const char *host, *page;
    struct http_req req;
    char *headers[99]; /* XXX */
    int num_headers;
    krb5_storage *sp;

    gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL;
    gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
    gss_name_t server = GSS_C_NO_NAME;
    gss_OID mech_oid, cred_mech_oid;
    OM_uint32 flags;
    OM_uint32 maj_stat, min_stat;

    setprogname(argv[0]);

    if(getarg(http_args, num_http_args, argc, argv, &optidx))
	usage(1);

    if (help_flag)
	usage (0);

    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    mech_oid = select_mech(mech);

    if (cred_mech_str)
	cred_mech_oid = select_mech(cred_mech_str);
    else
	cred_mech_oid = mech_oid;

    if (argc != 1 && argc != 2)
	errx(1, "usage: %s host [page]", getprogname());
    host = argv[0];
    if (argc == 2)
	page = argv[1];
    else
	page = "/";

    flags = 0;
    if (delegate_flag)
	flags |= GSS_C_DELEG_FLAG;
    if (policy_flag)
	flags |= GSS_C_DELEG_POLICY_FLAG;
    if (mutual_flag)
	flags |= GSS_C_MUTUAL_FLAG;

    done = 0;
    num_headers = 0;
    gssapi_done = 0;
    gssapi_started = 0;

    if (client_str) {
	gss_buffer_desc name_buffer;
	gss_name_t name;
	gss_OID_set mechset = GSS_C_NO_OID_SET;

	name_buffer.value = client_str;
	name_buffer.length = strlen(client_str);

	maj_stat = gss_import_name(&min_stat, &name_buffer, GSS_C_NT_USER_NAME, &name);
	if (maj_stat)
	    errx(1, "failed to import name");

	if (cred_mech_oid) {
	    gss_create_empty_oid_set(&min_stat, &mechset);
	    gss_add_oid_set_member(&min_stat, cred_mech_oid, &mechset);
	}
	
	maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE,
				    mechset, GSS_C_INITIATE,
				    &client_cred, NULL, NULL);
	gss_release_name(&min_stat, &name);
	gss_release_oid_set(&min_stat, &mechset);
	if (maj_stat)
	    errx(1, "failed to find cred of name %s", client_str);
    }

    {
	gss_buffer_desc name_token;
	char *name;
	asprintf(&name, "%s@%s", gss_service, host);
	name_token.length = strlen(name);
	name_token.value = name;
	
	maj_stat = gss_import_name(&min_stat,
				   &name_token,
				   GSS_C_NT_HOSTBASED_SERVICE,
				   &server);
	if (GSS_ERROR(maj_stat))
	    gss_err (1, min_stat, "gss_inport_name: %s", name);
	free(name);
    }

    s = do_connect(host, port_str);
    if (s < 0)
	errx(1, "connection failed");

    sp = krb5_storage_from_fd(s);
    if (sp == NULL)
	errx(1, "krb5_storage_from_fd");

    do {
	print_body = 0;

	http_query(sp, host, page, headers, num_headers, &req);
	for (i = 0 ; i < num_headers; i++)
	    free(headers[i]);
	num_headers = 0;

	if (strstr(req.response, " 200 ") != NULL) {
	    print_body = 1;
	    done = 1;
	} else if (strstr(req.response, " 401 ") != NULL) {
	    if (http_find_header(&req, "WWW-Authenticate:") == NULL)
		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
	}

	if (!gssapi_done) {
	    const char *h = http_find_header(&req, "WWW-Authenticate:");
	    if (h == NULL)
		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);

	    if (strncasecmp(h, "Negotiate", 9) == 0) {
		gss_buffer_desc input_token, output_token;

		if (verbose_flag)
		    printf("Negotiate found\n");

		i = 9;
		while(h[i] && isspace((unsigned char)h[i]))
		    i++;
		if (h[i] != '\0') {
		    size_t len = strlen(&h[i]);
		    int slen;
		    if (len == 0)
			errx(1, "invalid Negotiate token");
		    input_token.value = emalloc(len);
		    slen = base64_decode(&h[i], input_token.value);
		    if (slen < 0)
			errx(1, "invalid base64 Negotiate token %s", &h[i]);
		    input_token.length = slen;
		} else {
		    if (gssapi_started)
			errx(1, "Negotiate already started");
		    gssapi_started = 1;

		    input_token.length = 0;
		    input_token.value = NULL;
		}

		if (strstr(req.response, " 200 ") != NULL)
		    sleep(1);

		maj_stat =
		    gss_init_sec_context(&min_stat,
					 client_cred,
					 &context_hdl,
					 server,
					 mech_oid,
					 flags,
					 0,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &input_token,
					 NULL,
					 &output_token,
					 NULL,
					 NULL);
		if (maj_stat == GSS_S_CONTINUE_NEEDED) {

		} else if (maj_stat == GSS_S_COMPLETE) {
		    gss_name_t targ_name, src_name;
		    gss_buffer_desc name_buffer;
		    gss_OID mech_type;

		    gssapi_done = 1;

		    maj_stat = gss_inquire_context(&min_stat,
						   context_hdl,
						   &src_name,
						   &targ_name,
						   NULL,
						   &mech_type,
						   NULL,
						   NULL,
						   NULL);
		    if (GSS_ERROR(maj_stat))
			gss_err (1, min_stat, "gss_inquire_context");

		    printf("Negotiate done: %s\n", mech);

		    maj_stat = gss_display_name(&min_stat,
						src_name,
						&name_buffer,
						NULL);
		    if (GSS_ERROR(maj_stat))
			gss_print_errors(min_stat);
		    else
			printf("Source: %.*s\n",
			       (int)name_buffer.length,
			       (char *)name_buffer.value);

		    gss_release_buffer(&min_stat, &name_buffer);

		    maj_stat = gss_display_name(&min_stat,
						targ_name,
						&name_buffer,
						NULL);
		    if (GSS_ERROR(maj_stat))
			gss_print_errors(min_stat);
		    else
			printf("Target: %.*s\n",
			       (int)name_buffer.length,
			       (char *)name_buffer.value);

		    gss_release_name(&min_stat, &targ_name);
		    gss_release_buffer(&min_stat, &name_buffer);
		} else {
		    gss_err (1, min_stat, "gss_init_sec_context");
		}


		if (output_token.length) {
		    char *neg_token;

		    base64_encode(output_token.value,
				  (int)output_token.length,
				  &neg_token);

		    asprintf(&headers[0], "Authorization: Negotiate %s",
			     neg_token);

		    num_headers = 1;
		    free(neg_token);
		    gss_release_buffer(&min_stat, &output_token);
		}
		if (input_token.length)
		    free(input_token.value);

	    } else
		done = 1;
	} else
	    done = 1;

	if (print_body || verbose_flag)
	    printf("%.*s\n", (int)req.body_size, (char *)req.body);

	http_req_free(&req);
    } while (!done);

    if (gssapi_done == 0)
	errx(1, "gssapi not done but http dance done");

    krb5_storage_free(sp);
    close(s);

    return 0;
}
Ejemplo n.º 29
0
/*
 * this code uses the userland rpcsec gss library to create a krb5
 * context on behalf of the kernel
 */
static void
process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
		    char *service)
{
	CLIENT			*rpc_clnt = NULL;
	AUTH			*auth = NULL;
	struct authgss_private_data pd;
	gss_buffer_desc		token;
	int			err, downcall_err = -EACCES;
	OM_uint32		maj_stat, min_stat, lifetime_rec;
	pid_t			pid, childpid = -1;
	gss_name_t		gacceptor = GSS_C_NO_NAME;
	gss_OID			mech;
	gss_buffer_desc		acceptor  = {0};

	token.length = 0;
	token.value = NULL;
	memset(&pd, 0, sizeof(struct authgss_private_data));

	/*
	 * If "service" is specified, then the kernel is indicating that
	 * we must use machine credentials for this request.  (Regardless
	 * of the uid value or the setting of root_uses_machine_creds.)
	 * If the service value is "*", then any service name can be used.
	 * Otherwise, it specifies the service name that should be used.
	 * (For now, the values of service will only be "*" or "nfs".)
	 *
	 * Restricting gssd to use "nfs" service name is needed for when
	 * the NFS server is doing a callback to the NFS client.  In this
	 * case, the NFS server has to authenticate itself as "nfs" --
	 * even if there are other service keys such as "host" or "root"
	 * in the keytab.
	 *
	 * Another case when the kernel may specify the service attribute
	 * is when gssd is being asked to create the context for a
	 * SETCLIENT_ID operation.  In this case, machine credentials
	 * must be used for the authentication.  However, the service name
	 * used for this case is not important.
	 *
	 */
	if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
				service == NULL)) {

		/* already running as uid 0 */
		if (uid == 0)
			goto no_fork;

		pid = fork();
		switch(pid) {
		case 0:
			/* Child: fall through to rest of function */
			childpid = getpid();
			unsetenv("KRB5CCNAME");
			printerr(2, "CHILD forked pid %d \n", childpid);
			break;
		case -1:
			/* fork() failed! */
			printerr(0, "WARNING: unable to fork() to handle"
				"upcall: %s\n", strerror(errno));
			return;
		default:
			/* Parent: just wait on child to exit and return */
			do {
				pid = wait(&err);
			} while(pid == -1 && errno != -ECHILD);

			if (WIFSIGNALED(err))
				printerr(0, "WARNING: forked child was killed"
					 "with signal %d\n", WTERMSIG(err));
			return;
		}
no_fork:

		auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err,
						&err, &rpc_clnt);
		if (err)
			goto out_return_error;
	}
	if (auth == NULL) {
		if (uid == 0 && (root_uses_machine_creds == 1 ||
				service != NULL)) {
			auth =	krb5_use_machine_creds(clp, uid, tgtname,
							service, &rpc_clnt);
			if (auth == NULL)
				goto out_return_error;
		} else {
			/* krb5_not_machine_creds logs the error */
			goto out_return_error;
		}
	}

	if (!authgss_get_private_data(auth, &pd)) {
		printerr(1, "WARNING: Failed to obtain authentication "
			    "data for user with uid %d for server %s\n",
			 uid, clp->servername);
		goto out_return_error;
	}

	/* Grab the context lifetime and acceptor name out of the ctx. */
	maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor,
				       &lifetime_rec, &mech, NULL, NULL, NULL);

	if (maj_stat != GSS_S_COMPLETE) {
		printerr(1, "WARNING: Failed to inquire context "
			    "maj_stat (0x%x)\n", maj_stat);
		lifetime_rec = 0;
	} else {
		get_hostbased_client_buffer(gacceptor, mech, &acceptor);
		gss_release_name(&min_stat, &gacceptor);
	}

	/*
	 * The serialization can mean turning pd.pd_ctx into a lucid context. If
	 * that happens then the pd.pd_ctx will be unusable, so we must never
	 * try to use it after this point.
	 */
	if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
		printerr(1, "WARNING: Failed to serialize krb5 context for "
			    "user with uid %d for server %s\n",
			 uid, clp->servername);
		goto out_return_error;
	}

	do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor);

out:
	gss_release_buffer(&min_stat, &acceptor);
	if (token.value)
		free(token.value);
#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
	if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
		authgss_free_private_data(&pd);
#endif
	if (auth)
		AUTH_DESTROY(auth);
	if (rpc_clnt)
		clnt_destroy(rpc_clnt);

	pid = getpid();
	if (pid == childpid)
		exit(0);
	else
		return;

out_return_error:
	do_error_downcall(fd, uid, downcall_err);
	goto out;
}