Exemple #1
0
int gsscon_write_token (int         inSocket, 
                const char *inTokenValue, 
                size_t      inTokenLength)
{
    int err = 0;
    u_int32_t tokenLength = htonl (inTokenLength);

    if (!inTokenValue) { err = EINVAL; }
    
    if (!err) {
	err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
    }
        
    if (!err) { 
        err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
    }
    
    if (!err) {
    //    printf ("Wrote token:\n");
    //    PrintBuffer (inTokenValue, inTokenLength);

    } else { 
        gsscon_print_error (err, "gsscon_write_token() failed");
    }
   
    return err;
}
Exemple #2
0
static int ReadBuffer (int     inSocket, 
                       size_t  inBufferLength, 
                       char   *ioBuffer)
{
    int err = 0;
    ssize_t bytesRead = 0;
    
    if (!ioBuffer) { err = EINVAL; }
    
    if (!err) {
        char *ptr = ioBuffer;
        do {
            ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
            if (count < 0) {
                /* Try again on EINTR */
                if (errno != EINTR) { err = errno; }
            } else if (count == 0) {
                err = ECONNRESET; /* EOF and we expected data */
            } else {
                ptr += count;
                bytesRead += count;
            }
        } while (!err && (bytesRead < inBufferLength));
    } 
    
    if (err) { gsscon_print_error (err, "ReadBuffer failed"); }

    return err;
}
Exemple #3
0
static int WriteBuffer (int         inSocket, 
                        const char *inBuffer, 
                        size_t      inBufferLength)
{
    int err = 0;
    ssize_t bytesWritten = 0;
    
    if (!inBuffer) { err = EINVAL; }
    
    if (!err) {
        const char *ptr = inBuffer;
        do {
            ssize_t count;

            count = write (inSocket, ptr, inBufferLength - bytesWritten);

            if (count < 0) {
                /* Try again on EINTR */
                if (errno != EINTR) { err = errno; }
            } else {
                ptr += count;
                bytesWritten += count;
            }
        } while (!err && (bytesWritten < inBufferLength));
    } 
    
    if (err) { gsscon_print_error (err, "WriteBuffer failed"); }

    return err;
}
Exemple #4
0
int gsscon_write_encrypted_token (int                 inSocket, 
                         const gss_ctx_id_t  inContext, 
                         const char         *inToken, 
                         size_t              inTokenLength)
{
    int err = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0;
    gss_buffer_desc outputBuffer = { 0, NULL };
    
    if (!inContext) { err = EINVAL; }
    if (!inToken  ) { err = EINVAL; }
    
    if (!err) {
        gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
        int encrypt = 1;   /* do encryption and integrity protection */
        int encrypted = 0; /* did mechanism encrypt/integrity protect? */
        
        majorStatus = gss_wrap (&minorStatus, 
                                inContext, 
                                encrypt, 
                                GSS_C_QOP_DEFAULT,
                                &inputBuffer, 
                                &encrypted, 
                                &outputBuffer);
        if (majorStatus != GSS_S_COMPLETE) { 
            gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
            err = minorStatus ? minorStatus : majorStatus; 
        } else if (!encrypted) {
            fprintf (stderr, "WARNING!  Mechanism does not support encryption!");
            err = EINVAL; /* You may not want to fail here. */
        }
    }
    
    if (!err) {
      //  printf ("Unencrypted token:\n");
      //  PrintBuffer (inToken, inTokenLength);
	err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
    }
    
    if (!err) {
    } else { 
        gsscon_print_error (err, "gsscon_write_token failed");
    }
    
    if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
    
    return err;
}
Exemple #5
0
int gsscon_read_token (int      inSocket, 
               char   **outTokenValue, 
               size_t  *outTokenLength)
{
    int err = 0;
    char *token = NULL;
    u_int32_t tokenLength = 0;
    
    if (!outTokenValue ) { err = EINVAL; }
    if (!outTokenLength) { err = EINVAL; }
    
    if (!err) {
        err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
    }
    
    if (!err) {
	tokenLength = ntohl (tokenLength);
	token = malloc (tokenLength);
        if (token==NULL) {
          err=EIO;
        } else {
          memset (token, 0, tokenLength); 
        
          err = ReadBuffer (inSocket, tokenLength, token);
        }
    }
    
    if (!err) {
	*outTokenLength = tokenLength;
        *outTokenValue = token;        
        token = NULL; /* only free on error */
    } else { 
        gsscon_print_error (err, "ReadToken failed"); 
    }

    if (token) { free (token); }
    
    return err;
}
Exemple #6
0
int gsscon_connect (const char *inHost, unsigned int inPort, const char *inServiceName, int *outFD, gss_ctx_id_t *outGSSContext)
{
  int err = 0;
  int fd = -1;
  OM_uint32 majorStatus;
  OM_uint32 minorStatus = 0, minorStatusToo = 0;
  struct addrinfo *ai=NULL;
  struct addrinfo *ai_head=NULL;
  struct addrinfo hints={.ai_family=AF_UNSPEC, .ai_socktype=SOCK_STREAM, .ai_protocol=IPPROTO_TCP};
  struct sockaddr_in saddr;
  char *port=NULL;
  gss_name_t serviceName = NULL;
  gss_name_t clientName = NULL;
  gss_cred_id_t clientCredentials = GSS_C_NO_CREDENTIAL;
  gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
  OM_uint32 actualFlags = 0;
  char *inputTokenBuffer = NULL;
  size_t inputTokenBufferLength = 0;
  gss_buffer_desc inputToken;  /* buffer received from the server */
  gss_buffer_desc nameBuffer;
  gss_buffer_t inputTokenPtr = GSS_C_NO_BUFFER;
  char *name;

  if (!inServiceName) { err = EINVAL; }
  if (!outGSSContext) { err = EINVAL; }
    
  if (!err) {
    /* get a string for getaddrinfo */
    if (asprintf(&port, "%d", inPort)>0) { 
      err=getaddrinfo(inHost, port, &hints, &ai_head);
      free(port);
    } else
      err=1;
  }
    
  if (!err) {
    /* try all options returned until one works */
    for (ai=ai_head,fd=-1; (ai!=NULL) && (fd==-1); ai=ai->ai_next) {
      fd=socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      if (fd < 0) {
        fd=-1;
        continue;
      }

      fprintf(stderr, "gss_connect: Connecting to host '%s' on port %d\n", inHost, inPort);
      err=connect(fd, ai->ai_addr, ai->ai_addrlen);
      if (err!=0) {
        close(fd);
        fd=-1;
        continue;
      }
    }

    if (fd==-1)
      err=1;
  }
    
  if (!err) {
    *outFD = fd;
    fd = -1; /* takes ownership */
  } else {
    gsscon_print_error (err, "OpenConnection failed");
  }
    
  if (fd >= 0) { close (fd); }

  if (!err) {
    majorStatus = gss_acquire_cred (&minorStatus, clientName, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, 
                                    GSS_C_INITIATE, &clientCredentials, NULL, NULL); 
    if (majorStatus != GSS_S_COMPLETE) { 
      gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
      err = minorStatus ? minorStatus : majorStatus; 
    }
  }
    
  /*
   * Here is where the client picks the service principal it will
   * try to use to connect to the server.  In the case of the
   * gssClientSample, the service principal is passed in on the
   * command line, however, in a real world example, this would be
   * unacceptable from a user interface standpoint since the user
   * shouldn't need to know the server's service principal.
   * 
   * In traditional Kerberos setups, the service principal would be
   * constructed from the type of the service (eg: "imap"), the DNS
   * hostname of the server (eg: "mailserver.domain.com") and the
   * client's local realm (eg: "DOMAIN.COM") to form a full
   * principal string (eg: "imap/[email protected]").
   *
   * Now that many sites do not have DNS, this setup is becoming
   * less common.  However you decide to generate the service
   * principal, you need to adhere to the following constraint: The
   * service principal must be constructed by the client, typed in
   * by the user or administrator, or transmitted to the client in a
   * secure manner from a trusted third party -- such as through an
   * encrypted connection to a directory server.  You should not
   * have the server send the client the service principal name as
   * part of the authentication negotiation.
   *
   * The reason you can't let the server tell the client which
   * principal to use is that many machines at a site will have
   * their own service principal and keytab which identifies the
   * machine -- in a Windows Active Directory environment all
   * machines have a service principal and keytab.  Some of these
   * machines (such as a financial services server) will be more
   * trustworthy than others (such as a random machine on a
   * coworker's desk).  If the owner of one of these untrustworthy
   * machines can trick the client into using the untrustworthy
   * machine's principal instead of the financial services server's
   * principal, then he can trick the client into authenticating and
   * connecting to the untrustworthy machine.  The untrustworthy
   * machine can then harvest any confidential information the
   * client sends to it, such as credit card information or social
   * security numbers.
   *
   * If your protocol already involves sending the service principal
   * as part of your authentication negotiation, your client should
   * cache the name it gets after the first successful
   * authentication so that the problem above can only happen on the
   * first connection attempt -- similar to what ssh does with host
   * keys.
   */
    
  if (!err) {
    nameBuffer.length = asprintf(&name, "%s@%s", inServiceName, inHost);
    nameBuffer.value = name;

    majorStatus = gss_import_name (&minorStatus, &nameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName); 
    if (majorStatus != GSS_S_COMPLETE) { 
      gsscon_print_gss_errors ("gss_import_name(inServiceName)", majorStatus, minorStatus);
      err = minorStatus ? minorStatus : majorStatus; 
    }
  }
    
  /* 
   * The main authentication loop:
   *
   * GSS is a multimechanism API.  Because the number of packet
   * exchanges required to authenticate can vary between mechanisms,
   * we need to loop calling gss_init_sec_context, passing the
   * "input tokens" received from the server and send the resulting
   * "output tokens" back until we get GSS_S_COMPLETE or an error.
   */

  majorStatus = GSS_S_CONTINUE_NEEDED;

  gss_OID_desc EAP_OID = { 9, "\x2B\x06\x01\x05\x05\x0F\x01\x01\x11" };
 
  while (!err && (majorStatus != GSS_S_COMPLETE)) {
    gss_buffer_desc outputToken = { 0, NULL }; /* buffer to send to the server */
    OM_uint32 requestedFlags = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | 
                                GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
        
    majorStatus = gss_init_sec_context (&minorStatus, 
                                        clientCredentials, 
                                       &gssContext, 
                                        serviceName, 
                                       &EAP_OID /* mech_type */,
                                        requestedFlags, 
                                        GSS_C_INDEFINITE, 
                                        GSS_C_NO_CHANNEL_BINDINGS, 
                                        inputTokenPtr,
                                        NULL /* actual_mech_type */, 
                                       &outputToken, 
                                       &actualFlags, 
                                        NULL /* time_rec */);
        
    /* Send the output token to the server (even on error) */
    if ((outputToken.length > 0) && (outputToken.value != NULL)) {
      err = gsscon_write_token (*outFD, outputToken.value, outputToken.length);
            
      /* free the output token */
      gss_release_buffer (&minorStatusToo, &outputToken);
    }
        
    if (!err) {
      if (majorStatus == GSS_S_CONTINUE_NEEDED) { 
        /* Protocol requires another packet exchange */
                
        /* Clean up old input buffer */
        if (inputTokenBuffer) {
          free (inputTokenBuffer);
          inputTokenBuffer = NULL;  /* don't double-free */
        }
                
        /* Read another input token from the server */
        err = gsscon_read_token (*outFD, &inputTokenBuffer, &inputTokenBufferLength);
                
        if (!err) {
          /* Set up input buffers for the next run through the loop */
          inputToken.value = inputTokenBuffer;
          inputToken.length = inputTokenBufferLength;
          inputTokenPtr = &inputToken;
        }
      } else if (majorStatus != GSS_S_COMPLETE) {
        gsscon_print_gss_errors ("gss_init_sec_context", majorStatus, minorStatus);
        err = minorStatus ? minorStatus : majorStatus; 
      }
    }
  }
    
  if (!err) { 
    *outGSSContext = gssContext;
    gssContext = NULL;
  } else {
    gsscon_print_error (err, "AuthenticateToServer failed"); 
  }

  if (inputTokenBuffer) { free (inputTokenBuffer); }
  if (serviceName     ) { gss_release_name (&minorStatus, &serviceName); }
  if (clientName      ) { gss_release_name (&minorStatus, &clientName); }
  if (ai_head         ) { freeaddrinfo(ai_head); }

  if (clientCredentials != GSS_C_NO_CREDENTIAL) { 
    gss_release_cred (&minorStatus, &clientCredentials); }
  if (gssContext != GSS_C_NO_CONTEXT) { 
    gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }

  return err;
}
Exemple #7
0
int gsscon_read_encrypted_token (int                  inSocket, 
                        const gss_ctx_id_t   inContext, 
                        char               **outTokenValue, 
                        size_t              *outTokenLength)
{
    int err = 0;
    char *token = NULL;
    size_t tokenLength = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0;
    gss_buffer_desc outputBuffer = { 0 , NULL};
    char *unencryptedToken = NULL;
    
    if (!inContext     ) { err = EINVAL; }
    if (!outTokenValue ) { err = EINVAL; }
    if (!outTokenLength) { err = EINVAL; }
    
    if (!err) {
        err = gsscon_read_token (inSocket, &token, &tokenLength);
    }
    
    if (!err) {
        gss_buffer_desc inputBuffer = { tokenLength, token};
        int encrypted = 0; /* did mechanism encrypt/integrity protect? */

        majorStatus = gss_unwrap (&minorStatus, 
                                  inContext, 
                                  &inputBuffer, 
                                  &outputBuffer, 
                                  &encrypted, 
                                  NULL /* qop_state */);
        if (majorStatus != GSS_S_COMPLETE) { 
            gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
            err = minorStatus ? minorStatus : majorStatus; 
        } else if (!encrypted) {
            fprintf (stderr, "WARNING!  Mechanism not using encryption!");
            err = EINVAL; /* You may not want to fail here. */
        }
    }
    
    if (!err) {
        unencryptedToken = malloc (outputBuffer.length);
        if (unencryptedToken == NULL) { err = ENOMEM; }
    }
    
    if (!err) {
        memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
        
	// printf ("Unencrypted token:\n");
        // PrintBuffer (unencryptedToken, outputBuffer.length);
        
	*outTokenLength = outputBuffer.length;
        *outTokenValue = unencryptedToken;
        unencryptedToken = NULL; /* only free on error */
        
    } else { 
        gsscon_print_error (err, "ReadToken failed"); 
    }
    
    if (token             ) { free (token); }
    if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
    if (unencryptedToken  ) { free (unencryptedToken); }
    
    return err;
}
int gsscon_passive_authenticate (int	            inSocket, 
				 gss_buffer_desc    inNameBuffer,
				 gss_ctx_id_t      *outGSSContext,
				 client_cb_fn       clientCb,
				 void              *clientCbData)
{
    int err = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0, minorStatusToo = 0;
    gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
    gss_name_t clientName = GSS_C_NO_NAME, serviceName = GSS_C_NO_NAME;
    gss_cred_id_t acceptorCredentials = NULL;
    gss_buffer_desc clientDisplayName = {0, NULL};
    char *inputTokenBuffer = NULL;
    size_t inputTokenBufferLength = 0;
    gss_buffer_desc inputToken;  /* buffer received from the server */
    
    printf("In gsscon_passive_authenticate(), inNameBuffer = %s\n", inNameBuffer.value);

    if (inSocket <  0 ) { err = EINVAL; }
    if (!outGSSContext) { err = EINVAL; }

    if (!err)
      majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName); 
    if (majorStatus != GSS_S_COMPLETE) {
	gsscon_print_gss_errors ("gss_import_name(serviceName)", majorStatus, minorStatus);
	err = minorStatus ? minorStatus : majorStatus; 
      }

    if (!err) {
      majorStatus = gss_acquire_cred ( &minorStatus, serviceName,
				       GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
				       GSS_C_ACCEPT, &acceptorCredentials,
				       NULL /*mechs out*/, NULL /*time out*/);
      if (majorStatus != GSS_S_COMPLETE) { 
	gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
	err = minorStatus ? minorStatus : majorStatus; 
      }
    }

    /* 
     * The main authentication loop:
     *
     * GSS is a multimechanism API.  The number of packet exchanges required to  
     * authenticatevaries between mechanisms.  As a result, we need to loop reading 
     * input tokens from the client, calling gss_accept_sec_context on the input 
     * tokens and send the resulting output tokens back to the client until we 
     * get GSS_S_COMPLETE or an error.
     *
     * When we are done, save the client principal so we can make authorization 
     * checks.
     */
    
    majorStatus = GSS_S_CONTINUE_NEEDED;
    while (!err && (majorStatus != GSS_S_COMPLETE)) {
        /* Clean up old input buffer */
        if (inputTokenBuffer != NULL) {
            free (inputTokenBuffer);
            inputTokenBuffer = NULL;  /* don't double-free */
        }
        
        err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
        
        if (!err) {
            /* Set up input buffers for the next run through the loop */
            inputToken.value = inputTokenBuffer;
            inputToken.length = inputTokenBufferLength;
        }
        
        if (!err) {
            /* buffer to send to the server */
            gss_buffer_desc outputToken = { 0, NULL }; 
            
            /*
             * accept_sec_context does the actual work of taking the client's 
             * request and generating an appropriate reply.              */
            majorStatus = gss_accept_sec_context (&minorStatus, 
                                                  &gssContext, 
						  acceptorCredentials,
                                                  &inputToken, 
                                                  GSS_C_NO_CHANNEL_BINDINGS, 
                                                  &clientName,
                                                  NULL /* actual_mech_type */,
                                                  &outputToken, 
                                                  NULL /* req_flags */, 
                                                  NULL /* time_rec */, 
                                                  NULL /* delegated_cred_handle */);
            
            if ((outputToken.length > 0) && (outputToken.value != NULL)) {
                /* Send the output token to the client (even on error) */
                err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
                
                /* free the output token */
                gss_release_buffer (&minorStatusToo, &outputToken);
            }
        }
        
        if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
            gsscon_print_gss_errors ("gss_accept_sec_context", majorStatus, minorStatus);
            err = minorStatus ? minorStatus : majorStatus; 
        }            
    }

    if (!err) {
      majorStatus = gss_display_name(&minorStatus, clientName, &clientDisplayName, NULL);
      if (GSS_ERROR(majorStatus)) {
	gsscon_print_gss_errors("gss_display_name", majorStatus, minorStatus);
	err = EINVAL;
      }
      if (!err)
	err = clientCb(clientName, &clientDisplayName, clientCbData);
    }

    if (!err) { 
        *outGSSContext = gssContext;
        gssContext = NULL;
    } else {
        gsscon_print_error (err, "Authenticate failed");
    }
    
    if (inputTokenBuffer) { free (inputTokenBuffer); }
    if (gssContext != GSS_C_NO_CONTEXT) { 
        gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
if (clientName != GSS_C_NO_NAME)
  gss_release_name(&minorStatus, &clientName);
if (clientDisplayName.value != NULL)
  gss_release_buffer(&minorStatus, &clientDisplayName);
 gss_release_name( &minorStatus, &serviceName);
 gss_release_cred( &minorStatus, &acceptorCredentials);
        
    return err;
}