home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / security / winnt / httpauth / get_sock.c < prev    next >
C/C++ Source or Header  |  1997-10-08  |  12KB  |  472 lines

  1. /*++
  2.  
  3. Copyright 1996-1997 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     get_sock.c
  8.  
  9. Abstract:
  10.  
  11.     This does a get using raw sockets
  12.  
  13. History:
  14.  
  15.     09-Nov-1995     Created
  16.     15-Feb-1996     Added authentication support
  17.  
  18. --*/
  19.  
  20. #include <windows.h>
  21. #include <winsock.h>
  22.  
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <tchar.h>
  28. #include <io.h>
  29. #include <fcntl.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #include "httpauth.h"
  34.  
  35. // globals
  36.  
  37. #define HD_AUTHENTICATE         "WWW-Authenticate:"
  38. #define HD_LENGTH               "Content-Length:"
  39. #define HD_CONNECTION           "Connection:"
  40.  
  41. // list of Authentication methods to support
  42.  
  43. char      achAuth[256];
  44.  
  45.  
  46. // Helper functions
  47.  
  48. void SkipWhite(PSTR *ppS )
  49. {
  50.     PSTR pS = *ppS;
  51.  
  52.     while ( *pS && isspace(*pS) )
  53.         ++pS;
  54.  
  55.     *ppS = pS;
  56. }
  57.  
  58.  
  59. void SkipNonWhite(PSTR *ppS )
  60. {
  61.     PSTR pS = *ppS;
  62.  
  63.     while ( *pS && !isspace(*pS) )
  64.         ++pS;
  65.  
  66.     *ppS = pS;
  67. }
  68.  
  69.  
  70.  
  71. BOOL
  72. HttpGetSocket(
  73.     char * Verb,
  74.     char * Server,
  75.     char * URL,
  76.     BOOL   DisplayHeaders,
  77.     DWORD  ClientDataSize,
  78.     PSTR   pchUserName,
  79.     PSTR   pchPassword,
  80.     PSTR   pszStore,
  81.     PSTR   pszPref
  82.     )
  83. /*++
  84.  
  85.  Routine Description:
  86.  
  87.     Issue a command to a HTTP server using authentication
  88.  
  89.  Arguments:
  90.  
  91.     Verb                HTTP command : GET / HEAD / ...
  92.     Server              server name
  93.     URL                 URL to send to the server
  94.     DisplayHeaders      TRUE to display headers as received
  95.     ClientDataSize      number of bytes to send in the request
  96.     pchUserName         user name for authentication
  97.     pchPassword         password for authentication
  98.     pszStore            file name where to dump reply from server
  99.  
  100.  Return Value:
  101.  
  102.     Returns TRUE is successful; otherwise FALSE is returned.
  103.  
  104. --*/
  105. {
  106.     char               ReceiveBuffer[8*1024];
  107.     int                Error;
  108.     BYTE               Request[1024];
  109.     int                RequestSize;
  110.     char *             AcceptTypes[2] = {"*/*", NULL};
  111.     SOCKET             Socket = INVALID_SOCKET;
  112.     WSADATA            WsaData;
  113.     struct sockaddr_in Address;
  114.     struct hostent *   HostEntry;
  115.     char               Headers[] = 
  116.                            "HTTP/1.0\r\n"
  117.                            "User-Agent: AuthClient\r\n"
  118.                            "Accept: */*\r\n";
  119.     char               CrLf[] = "\r\n";
  120.     BYTE               ClientData[64*1024];
  121.     BOOL               fKeepAlive = FALSE;
  122.     int                cRec;
  123.     DWORD              cLen;
  124.     BOOL               fInHeader;
  125.     PSTR               pchAuthData;
  126.     BOOL               fServerKeepAlive = FALSE;
  127.     BOOL               fNeedMoreData;
  128.     BOOL               fNeedAuthenticate;
  129.     PSTR               pH;
  130.     PSTR               pN;
  131.     BOOL               fStatusLine;
  132.     int                Status = -1;
  133.     DWORD              cToRead;
  134.     PSTR               paAuth = achAuth;
  135.     BOOL               fSt = FALSE;
  136.     int                hnd = EOF;
  137.  
  138.     Error = WSAStartup (0x101, &WsaData);
  139.  
  140.     if (Error == SOCKET_ERROR) 
  141.     {
  142.         fprintf(stderr, "Error in WSAStartup = %d\n", GetLastError());
  143.         return FALSE;
  144.     }
  145.  
  146.     if ( !InitAuthorizationHeader() )
  147.     {
  148.         fprintf(stderr, "Cannot initialize security module\n" );
  149.         return FALSE;
  150.     }
  151.  
  152.     memset( achAuth, '\0', sizeof(achAuth) );
  153.     pchAuthData = NULL;
  154.     fNeedAuthenticate = FALSE;
  155.  
  156.     //
  157.     // Connect to the server
  158.     //
  159.  
  160.     if  ( pszStore != NULL )
  161.         if ( (hnd = _open( pszStore, _O_BINARY | _O_CREAT | _O_TRUNC | _O_RDWR, S_IREAD|S_IWRITE )) == EOF )
  162.         {
  163.             fprintf( stderr, "Can't create file %s\n", pszStore );
  164.             return FALSE;
  165.         }
  166.  
  167. again:
  168.  
  169.     if ( Socket == INVALID_SOCKET )
  170.     {
  171.         Socket = socket(AF_INET, SOCK_STREAM, 0);
  172.  
  173.         if (Socket == INVALID_SOCKET) 
  174.         {
  175.             fprintf(stderr, "Error creating socket = %d\n", GetLastError());
  176.             fSt = FALSE;
  177.             goto ex;
  178.         }
  179.  
  180.         Address.sin_family = AF_INET;
  181.         Address.sin_port = 0;
  182.         Address.sin_addr.s_addr = INADDR_ANY;
  183.  
  184.         Error = 
  185.         bind(
  186.             Socket,
  187.             (struct sockaddr *) &Address,
  188.             sizeof(Address));
  189.  
  190.         if (Error) 
  191.         {
  192.             fprintf(stderr, "Error in bind = %d\n", GetLastError());
  193.             fSt = FALSE;
  194.             goto ex;
  195.         }
  196.  
  197.         Address.sin_family = AF_INET;
  198.         Address.sin_port = htons(80);
  199.         Address.sin_addr.s_addr = inet_addr(Server);
  200.  
  201.         if (Address.sin_addr.s_addr == -1) 
  202.         {
  203.             //
  204.             // Must be a server name
  205.             //
  206.             HostEntry = gethostbyname(Server);
  207.             if (HostEntry == NULL) 
  208.             {
  209.                 printf("unable to resolve %s\n", Server);
  210.                 fSt = FALSE;
  211.                 goto ex;
  212.             } else 
  213.             {
  214.                 Address.sin_addr.s_addr = *((unsigned long *) HostEntry->h_addr);
  215.             }
  216.         }
  217.  
  218.         Error =
  219.         connect(
  220.             Socket,
  221.             (struct sockaddr *) &Address,
  222.             sizeof(Address));
  223.  
  224.         if (Error) 
  225.         {
  226.             fprintf(stderr, "Error connecting to %s = %d\n", Server, GetLastError());
  227.             fSt = FALSE;
  228.             goto ex;
  229.         }
  230.     }
  231.  
  232.     //
  233.     // Send the client request
  234.     //
  235.  
  236.     strcpy(Request, Verb);
  237.     strcat(Request, " ");
  238.     strcat(Request, URL);
  239.     strcat(Request, " ");
  240.     strcat(Request, Headers);
  241.     if (ClientDataSize) 
  242.     {
  243.         sprintf(ClientData, "Content-Length: %d\r\n", ClientDataSize);
  244.         strcat(Request, ClientData);
  245.     }
  246.     if ( fKeepAlive )
  247.     {
  248.         strcat(Request, "Connection: Keep-Alive\r\n" );
  249.     }
  250.  
  251.     if ( !AddAuthorizationHeader( Request + strlen(Request), achAuth, pchAuthData, pchUserName, pchPassword, &fNeedMoreData ) )
  252.     {
  253.         printf( "Authentication failed\n" );
  254.         fSt = FALSE;
  255.         goto ex;
  256.     }
  257.  
  258.     strcat(Request, CrLf);
  259.  
  260.     RequestSize = strlen(Request);
  261.  
  262.     Error =
  263.     send(
  264.         Socket,
  265.         Request,
  266.         RequestSize,
  267.         0);
  268.  
  269.     if (Error != RequestSize) 
  270.     {
  271.         printf("Error in client send = %d, %d\n", Error, GetLastError());
  272.         fSt = FALSE;
  273.         goto ex;
  274.     }
  275.  
  276.     if (ClientDataSize) 
  277.     {
  278.         memset( ClientData, ' ', ClientDataSize );
  279.  
  280.         //
  281.         // Send the client data
  282.         //
  283.  
  284.         Error =
  285.         send(
  286.             Socket,
  287.             ClientData,
  288.             ClientDataSize,
  289.             0);
  290.  
  291.         if ( (DWORD)Error != ClientDataSize) 
  292.         {
  293.             printf("Error in client send = %d, %d\n", Error, GetLastError());
  294.             fSt = FALSE;
  295.             goto ex;
  296.         }
  297.     }
  298.  
  299.     // parse status & header
  300.  
  301.     cLen = (DWORD)-1;
  302.     fInHeader = TRUE;
  303.     fServerKeepAlive = FALSE;
  304.     fNeedAuthenticate = FALSE;
  305.  
  306.     for ( pH = ReceiveBuffer, fStatusLine = TRUE ; fInHeader ; )
  307.     {
  308.         cRec = recv( Socket, pH, ReceiveBuffer+sizeof(ReceiveBuffer)-pH, 0 );
  309.         if ( cRec <= 0 )
  310.         {
  311.             closesocket( Socket );
  312.             Socket = INVALID_SOCKET;
  313.             break;
  314.         }
  315.         pH[ cRec ] = '\0';
  316.  
  317.         // Iterate on header fields
  318.  
  319.         while ( pN = strstr(pH, "\r\n" ) )
  320.         {
  321.             *pN = '\0';
  322.  
  323.             if ( DisplayHeaders )
  324.             {
  325.                 printf( "%s\n", pH );
  326.             }
  327.  
  328.             if ( fStatusLine )
  329.             {
  330.                 // This is the status line, decode status
  331.  
  332.                 SkipNonWhite( &pH );
  333.                 SkipWhite( &pH );
  334.                 Status = atoi( pH );
  335.                 if ( Status == 401 )
  336.                 {
  337.                     fNeedAuthenticate = TRUE;
  338.                 }
  339.                 fStatusLine = FALSE;
  340.             }
  341.             else if ( pN == pH )    // end of header fields
  342.             {
  343.                 if ( hnd != EOF )
  344.                     write( hnd, pH+2, ReceiveBuffer+cRec-pH-2 );
  345.  
  346.                 cLen -= ( ReceiveBuffer+cRec-pH-2 );
  347.                 fInHeader = FALSE;
  348.                 break;
  349.             }
  350.             else if ( !strnicmp( pH, HD_AUTHENTICATE, sizeof(HD_AUTHENTICATE)-1 ) )
  351.             {
  352.                 SkipNonWhite( &pH );
  353.                 SkipWhite( &pH );
  354.  
  355.                 // check if we are already in the authentication sequence
  356.  
  357.                 if ( !IsInAuthorizationSequence() )
  358.                 {
  359.                     // append to list of supported authentication methods
  360.  
  361.                     strcpy( paAuth, pH );
  362.                     paAuth += strlen( pH ) + 1;
  363.                 }
  364.                 else
  365.                 {
  366.                     // store pointer to authenticate blob
  367.  
  368.                     SkipNonWhite( &pH );
  369.                     SkipWhite( &pH );
  370.                     pchAuthData = pH;
  371.                 }
  372.             }
  373.             else if ( !strnicmp( pH, HD_LENGTH, sizeof(HD_LENGTH)-1 ) )
  374.             {
  375.                 // get content length
  376.  
  377.                 SkipNonWhite( &pH );
  378.                 SkipWhite( &pH );
  379.                 cLen = atoi( pH );
  380.             }
  381.             else if ( !strnicmp( pH, HD_CONNECTION, sizeof(HD_CONNECTION)-1 ) )
  382.             {
  383.                 // check for keep-alive flag
  384.  
  385.                 SkipNonWhite( &pH );
  386.                 SkipWhite( &pH );
  387.                 if ( !strnicmp( pH, "Keep-Alive", sizeof("Keep-Alive")-1 ) )
  388.                     fServerKeepAlive = TRUE;
  389.             }
  390.  
  391.             pH = pN + 2;
  392.         }
  393.     }
  394.  
  395.     // add final delimiter to list of supported authentication methods
  396.  
  397.     if ( !IsInAuthorizationSequence() && fNeedAuthenticate )
  398.     {
  399.         *paAuth = '\0';
  400.  
  401.         // Insure specified methods are supported localy
  402.  
  403.         if ( !ValidateAuthenticationMethods( achAuth, pszPref ) )
  404.         {
  405.             // None of the server specified authentication methods
  406.             // are supported localy.
  407.  
  408.             SetLastError( ERROR_ACCESS_DENIED );
  409.  
  410.             fprintf( stderr, "No supported authentication method\n" );
  411.  
  412.             fSt = FALSE;
  413.             goto ex;
  414.         }
  415.     }
  416.  
  417.     // read message body
  418.  
  419.     if ( Socket != INVALID_SOCKET )
  420.     {
  421.         for ( ; cLen ; )
  422.         {
  423.             if ( (cToRead = sizeof(ReceiveBuffer)) > cLen )
  424.                 cToRead = cLen;
  425.             cRec = recv( Socket, ReceiveBuffer, cToRead, 0 );
  426.  
  427.             if ( cRec <= 0 )
  428.             {
  429.                 closesocket( Socket );
  430.                 Socket = INVALID_SOCKET;
  431.                 break;
  432.             }
  433.             if ( hnd != EOF )
  434.                 write( hnd, ReceiveBuffer, cRec );
  435.  
  436.             cLen -= cRec;
  437.         }
  438.     }
  439.  
  440.     if ( !fServerKeepAlive )
  441.     {
  442.         if ( IsInAuthorizationSequence() )
  443.         {
  444.             fprintf( stderr, "Authentication rejected by server\n" );
  445.  
  446.             fNeedAuthenticate = FALSE;  // authentication failed
  447.         }
  448.  
  449.         closesocket( Socket );
  450.         Socket = INVALID_SOCKET;
  451.     }
  452.  
  453.     if ( fNeedAuthenticate )
  454.     {
  455.         fKeepAlive = TRUE;
  456.         goto again;
  457.     }
  458.  
  459.     if ( Socket != INVALID_SOCKET )
  460.         closesocket(Socket);
  461.  
  462.     fSt = Status == 200;
  463.  
  464. ex:
  465.     TerminateAuthorizationHeader();
  466.  
  467.     if ( hnd != EOF )
  468.         close( hnd );
  469.  
  470.     return fSt;
  471. }
  472.