/*************************************************************************** netclient.cpp - description ------------------- begin : Thu Oct 26 2000 copyright : (C) 2000 by Franck Ladurelle email : ladurelf@partimage.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef MUST_LOGIN #include #endif #include "netclient.h" #include "exceptions.h" #include "common.h" // ================================================ CNetClient::CNetClient(bool bMustLogin, bool bUseSSL):CNet() { showDebug(9, "begin\n"); int sock; if (!(sock = socket(AF_INET, SOCK_STREAM, 0))) { showDebug(1, "socket error\n"); THROW(ERR_ERRNO, errno); } memset(&IdfServer.SockAddr, '\0', sizeof(struct sockaddr)); IdfServer.Sock = sock; #ifdef HAVE_SSL if (bUseSSL) { showDebug(3, "initializing client ssl\n"); SSLeay_add_ssl_algorithms(); meth = SSLv2_client_method(); SSL_load_error_strings(); ctx = SSL_CTX_new(meth); if (!ctx) THROW(ERR_SSL_CTX); m_bUseSSL = (ctx != NULL); } else m_bUseSSL = false; #else m_bUseSSL = false; #endif #ifdef MUST_LOGIN m_bMustLogin = bMustLogin; #else m_bMustLogin = false; #endif showDebug(9, "end constructor ok\n"); } void CNetClient::Connect(char * adr, unsigned short int port) { BEGIN; char * ok = (char *) malloc(5); char * szServerBanner = (char *) malloc (BANNER_SIZE+1); char * szBanner; char * explaination = (char *) malloc(8); struct hostent * host; if ((host = gethostbyname(adr)) == NULL) { showDebug(2, "connect error, gethostbyname() -> h_errno: %d\n", h_errno); /* FIXME: Perhaps we should provide the user with the details of h_errno */ THROW(ERR_HOST); } IdfServer.SockAddr.sin_family = AF_INET; IdfServer.SockAddr.sin_addr.s_addr = *(unsigned long *)host->h_addr; IdfServer.SockAddr.sin_port = htons(port); if (connect(IdfServer.Sock, (struct sockaddr *) &IdfServer.SockAddr, sizeof(IdfServer.SockAddr))) { showDebug(2, "connect error: %d\n", errno); THROW(ERR_ERRNO, errno); } showDebug(2, "connected, waiting for banner\n"); IdfServer.Ssl = NULL; // deactivate SSL until server allows it Recv(szServerBanner, BANNER_SIZE+1); // +1 -> preserve endding \0 showDebug(2, "Banner received: %s\n", szServerBanner); szBanner = Banner(m_bUseSSL, m_bMustLogin); Send(szBanner, BANNER_SIZE+1); showDebug(2, "Banner sent: %s\n", szBanner); free(szBanner); szBanner = NULL; Recv(ok, 5); if (strcmp(ok, " ack") && strcmp(ok, "nack")) showDebug(2, "Wrong answer from server: %s\n", ok); showDebug(3, "ok=%s\n", ok); if (strcmp(ok, " ack")) { free(ok); ok = NULL; Recv(explaination, 8); if (!strcmp(explaination, "banners")) { free(explaination); explaination = NULL; THROW(ERR_REFUSED); } else if (!strcmp(explaination, "toomany")) { free(explaination); explaination = NULL; THROW(ERR_TOOMANY); } else { free(explaination); explaination = NULL; THROW(ERR_VERSIONSMISMATCH); } } else { free(ok); ok = NULL; free(explaination); explaination = NULL; } #ifdef HAVE_SSL if (m_bUseSSL && strstr(szServerBanner, "SSL")) { int err; showDebug(1, "trying to use SSL as required\n"); free(szServerBanner); szServerBanner=NULL; IdfServer.Ssl = SSL_new(ctx); SSL_set_fd(IdfServer.Ssl, IdfServer.Sock); err = SSL_connect(IdfServer.Ssl); if (err == -1) { showDebug(1, "error ssl connect\n"); THROW(ERR_SSL_CONNECT); } showDebug(3, "ssl cipher: %s\n", SSL_get_cipher(IdfServer.Ssl)); } else { free(szServerBanner); szServerBanner=NULL; IdfServer.Ssl = NULL; showDebug(1, "no SSL because partimaged doesn't support it\n"); } #else showDebug(1, "not compiled with SSL\n"); IdfServer.Ssl = NULL; #endif showDebug(3, "connected to server\n"); } // return 0 if pass good else !0 // login/pass may be "nologin"/"nopass" if compiled with no login unsigned int CNetClient::SendPass(char * login, char * pass) { int nRes; unsigned int nSize; char * szSalt; char * szPasswd; char * ok = (char *) malloc(5); // send login nSize = strlen(login)+1; nRes = Send(&nSize, sizeof(unsigned int)); nRes = Send((void *) login, nSize); nRes = Recv(&nSize, sizeof(unsigned int)); szSalt = (char *) malloc (nSize); nRes = Recv(szSalt, nSize); #ifdef MUST_LOGIN #ifdef HAVE_PAM szPasswd = strdup(pass); #else szPasswd = crypt(pass, szSalt); #endif #else szPasswd = strdup(pass); #endif // send password nSize = strlen(szPasswd)+1; nRes = Send(&nSize, sizeof(unsigned int)); nRes = Send((void *) szPasswd, nSize); // check answer nRes = Recv(ok, 4+1); // preserve endding \0 *(ok+4) = '\0'; nRes = strcmp(ok, " ack"); free(ok); free(szSalt); return nRes; } CExceptions * CNetClient::RecvExcep(const char * msg) { DWORD dwArg1, dwArg2, dwErrCode, dwAux; char * szArg1; Recv(&dwErrCode, sizeof(dwErrCode)); Recv(&dwArg1, sizeof(dwArg1)); Recv(&dwArg2, sizeof(dwArg2)); Recv(&dwAux, sizeof(dwAux)); // strlen of szArg1 szArg1 = (char *) malloc(dwAux); Recv(szArg1, dwAux); return new CExceptions(msg, (signed int) dwErrCode, szArg1, dwArg1, dwArg2); }