Platform SDK: Active Directory, ADSI, and Directory Services |
For an RPC service, the RPC run time routine handles most of the details of mutual authentication. When the service starts up, it simply calls the RpcServerRegisterAuthInfo function to register its SPN and specify an authentication service. This example specifies the RPC_C_AUTHN_GSS_NEGOTIATE authentication service which performs the mutual authentication. The service then sets up the RPC bindings and waits for a client connection. When a client binds to the service, the RPC run time automatically performs the mutual authentication. If the client requests authentication and the client's credentials are invalid, the RPC run time does not dispatch the client's calls. Note, however, that if the client does not request the proper authentication level, the RPC run time dispatches the call without performing authentication. For this reason, your service must call the RpcBindingInqAuthClient function to verify the authentication parameters specified by the client.
The following code fragment composes the service's SPN and registers the service for authentication. For the SpnCompose source code, see Composing SPNs for an RpcNs Service.
RPC_STATUS status; DWORD dwStatus; TCHAR **pspn; ULONG ulSpn=1; dwStatus = SpnCompose(&pspn, &ulSpn); // Register with the authentication service status = RpcServerRegisterAuthInfo((TCHAR*)*pspn, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL);
If the client is authenticated, the service can call the RpcBindingInqAuthClient function to retrieve the security parameters specified by the client. This enables the service to enforce additional security requirements. For example, a service that uses mutual authentication should also require that communications between client and service be digitally signed and/or encrypted. The following code fragment calls the RpcBindingInqAuthClient function and rejects the client's call unless the client has specified the required authentication level.
boolean Shutdown() { RPC_STATUS rpcStatus; RPC_AUTHZ_HANDLE hAuth; TCHAR *pszSpn; ULONG ulAuthnLevel; ULONG ulAuthnSvc; ULONG ulAuthzSvc; _tprintf(TEXT("Shutdown called.\n")); rpcStatus = RpcBindingInqAuthClient( 0, &hAuth, &pszSpn, &ulAuthnLevel, // Authentication level requested by client &ulAuthnSvc, &ulAuthzSvc); if (rpcStatus != RPC_S_OK) { _tprintf(TEXT("RpcBindingInqAuthClient failed: %d\n"), rpcStatus); return false; } _tprintf(TEXT("Client SPN:%s\n"),pszSpn); RpcStringFree(&pszSpn); switch (ulAuthnLevel) { case RPC_C_AUTHN_LEVEL_DEFAULT: _tprintf(TEXT("Client Auth Level: DEFAULT\n")); return false; // Keep running case RPC_C_AUTHN_LEVEL_NONE: _tprintf(TEXT("Client Auth Level: NONE\n")); return false; // Keep running case RPC_C_AUTHN_LEVEL_CONNECT: _tprintf(TEXT("Client Auth Level: CONNECT\n")); return false; // Keep running case RPC_C_AUTHN_LEVEL_CALL: _tprintf(TEXT("Client Auth Level: CALL\n")); return false; // Keep running case RPC_C_AUTHN_LEVEL_PKT: _tprintf(TEXT("Client Auth Level: PACKET\n")); break; // Shutdown case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: _tprintf(TEXT("Client Auth Level: PACKET_INTEGRITY\n")); break; // Shutdown case RPC_C_AUTHN_LEVEL_PKT_PRIVACY: _tprintf(TEXT("Client Auth Level: PACKET_PRIVACY\n")); break; // Shutdown default: _tprintf(TEXT("Client Auth Level: UNKNOWN (%d)\n"), ulAuthnLevel); return true; } // Shut down. ReportStatusToSCMgr( SERVICE_STOP_PENDING, // Service state NO_ERROR, // Exit code 3000); // Wait hint _tprintf(TEXT("\nService shutting down by request.\n")); RpcMgmtStopServerListening(NULL); return true; }