зеркало из https://github.com/mozilla/pjs.git
577 строки
14 KiB
C
577 строки
14 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU General Public License Version 2 or later (the
|
|
* "GPL"), in which case the provisions of the GPL are applicable
|
|
* instead of those above. If you wish to allow use of your
|
|
* version of this file only under the terms of the GPL and not to
|
|
* allow others to use your version of this file under the MPL,
|
|
* indicate your decision by deleting the provisions above and
|
|
* replace them with the notice and other provisions required by
|
|
* the GPL. If you do not delete the provisions above, a recipient
|
|
* may use your version of this file under either the MPL or the
|
|
* GPL.
|
|
*/
|
|
#ifdef XP_UNIX
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/un.h>
|
|
#include <sys/stat.h>
|
|
#include <netinet/tcp.h>
|
|
#else
|
|
#ifdef XP_MAC
|
|
#else /* Windows */
|
|
#include <windows.h>
|
|
#include <winsock.h>
|
|
#include <direct.h>
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include "messages.h"
|
|
#include "cmtcmn.h"
|
|
#include "cmtutils.h"
|
|
#include "obscure.h"
|
|
#include <string.h>
|
|
|
|
#ifdef XP_UNIX
|
|
#define DIRECTORY_SEPARATOR '/'
|
|
#elif defined WIN32
|
|
#define DIRECTORY_SEPARATOR '\\'
|
|
#elif defined XP_MAC
|
|
#define DIRECTORY_SEPARATOR ':'
|
|
#endif
|
|
|
|
/* Local defines */
|
|
#define CARTMAN_PORT 11111
|
|
#define MAX_PATH_LEN 256
|
|
|
|
/* write to the cmnav.log */
|
|
#if 0
|
|
#define LOG(x); do { FILE *f; f=fopen("cmnav.log","a+"); if (f) { \
|
|
fprintf(f, x); fclose(f); } } while(0);
|
|
#define LOG_S(x); do { FILE *f; f=fopen("cmnav.log","a+"); if (f) { \
|
|
fprintf(f, "%s", x); fclose(f); } } while(0);
|
|
#define ASSERT(x); if (!(x)) { LOG("ASSERT:"); LOG(#x); LOG("\n"); exit(-1); }
|
|
#else
|
|
#define LOG(x); ;
|
|
#define LOG_S(x); ;
|
|
#define ASSERT(x); ;
|
|
#endif
|
|
|
|
/* On error, returns -1.
|
|
** On success, returns non-negative number of unobscured bytes in buf
|
|
*/
|
|
int
|
|
RecvInitObscureData(CMT_SocketFuncs *sockFuncs, CMTSocket sock,
|
|
SSMObscureObject * obj, void * buf, int bufSize )
|
|
{
|
|
SSMObscureBool done = 0;
|
|
int rv = -1;
|
|
|
|
do {
|
|
int cc;
|
|
cc = sockFuncs->recv(sock, buf, bufSize);
|
|
if (cc <= 0)
|
|
return -1;
|
|
rv = SSMObscure_RecvInit(obj, buf, cc, &done);
|
|
} while (!done);
|
|
return rv;
|
|
}
|
|
|
|
|
|
/* returns -1 on error, 0 on success. */
|
|
int
|
|
SendInitObscureData(CMT_SocketFuncs *sockFuncs, CMTSocket sock,
|
|
SSMObscureObject * obj)
|
|
{
|
|
unsigned char * initBuf = NULL;
|
|
int rv = -1;
|
|
|
|
do {
|
|
int bufLen;
|
|
int len;
|
|
int cc;
|
|
|
|
bufLen = SSMObscure_SendInit(obj, NULL);
|
|
if (bufLen <= 0)
|
|
break;
|
|
|
|
initBuf = (unsigned char *) malloc(bufLen);
|
|
if (!initBuf)
|
|
break;
|
|
|
|
len = SSMObscure_SendInit(obj, initBuf);
|
|
if (len != bufLen)
|
|
break;
|
|
|
|
cc = sockFuncs->send(sock, initBuf, len);
|
|
|
|
/* Note, this code assumes a blocking socket,
|
|
** and hence doesn't deal with short writes.
|
|
*/
|
|
if (cc < len)
|
|
break;
|
|
|
|
rv = 0;
|
|
|
|
} while (0);
|
|
|
|
if (initBuf) {
|
|
free(initBuf);
|
|
initBuf = NULL;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMObscureObject * InitClientObscureObject(CMT_SocketFuncs *sockFuncs,
|
|
CMTSocket sock)
|
|
{
|
|
SSMObscureObject * sobj = NULL;
|
|
unsigned char buf[512];
|
|
int rv = -1;
|
|
|
|
/* Create the obscuring object */
|
|
sobj = SSMObscure_Create(0);
|
|
if (!sobj) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Send the initialization data */
|
|
rv = SendInitObscureData(sockFuncs, sock, sobj);
|
|
if (rv < 0) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Receive the obscuring initialization data */
|
|
rv = RecvInitObscureData(sockFuncs, sock, sobj, buf, sizeof(buf));
|
|
if (rv < 0) {
|
|
goto loser;
|
|
}
|
|
|
|
return sobj;
|
|
loser:
|
|
if (sobj) {
|
|
SSMObscure_Destroy(sobj);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char*
|
|
getCurrWorkDir(char *buf, int maxLen)
|
|
{
|
|
#if defined WIN32
|
|
return _getcwd(buf, maxLen);
|
|
#elif defined XP_UNIX
|
|
return getcwd(buf, maxLen);
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
setWorkingDir(char *path)
|
|
{
|
|
#if defined WIN32
|
|
_chdir(path);
|
|
#elif defined XP_UNIX
|
|
chdir(path);
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
static CMTStatus
|
|
launch_psm(char *executable)
|
|
{
|
|
char command[MAX_PATH_LEN];
|
|
#ifdef WIN32
|
|
STARTUPINFO sui;
|
|
PROCESS_INFORMATION pi;
|
|
UNALIGNED long *posfhnd;
|
|
int i;
|
|
char *posfile;
|
|
|
|
sprintf(command,"%s > psmlog", executable);
|
|
ZeroMemory( &sui, sizeof(sui) );
|
|
sui.cb = sizeof(sui);
|
|
sui.cbReserved2 = (WORD)(sizeof( int ) + (3 * (sizeof( char ) +
|
|
sizeof( long ))));
|
|
sui.lpReserved2 = calloc( sui.cbReserved2, 1 );
|
|
*((UNALIGNED int *)(sui.lpReserved2)) = 3;
|
|
posfile = (char *)(sui.lpReserved2 + sizeof( int ));
|
|
posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int ) +
|
|
(3 * sizeof( char )));
|
|
|
|
for ( i = 0, posfile = (char *)(sui.lpReserved2 + sizeof( int )),
|
|
posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int ) + (3 * sizeof( char ))) ;
|
|
i < 3 ; i++, posfile++, posfhnd++ ) {
|
|
|
|
*posfile = 0;
|
|
*posfhnd = (long)INVALID_HANDLE_VALUE;
|
|
}
|
|
/* Now, fire up PSM */
|
|
if (!CreateProcess(NULL, command, NULL, NULL, TRUE, DETACHED_PROCESS,
|
|
NULL, NULL, &sui, &pi)) {
|
|
goto loser;
|
|
}
|
|
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
#elif defined XP_UNIX
|
|
sprintf(command,"./%s &", executable);
|
|
if (system(command) == -1) {
|
|
goto loser;
|
|
}
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
#else
|
|
return CMTFailure;
|
|
#endif
|
|
}
|
|
|
|
PCMT_CONTROL CMT_EstablishControlConnection(char *inPath,
|
|
CMT_SocketFuncs *sockFuncs,
|
|
CMT_MUTEX *mutex)
|
|
{
|
|
PCMT_CONTROL control;
|
|
char *executable;
|
|
char *newWorkingDir;
|
|
char oldWorkingDir[MAX_PATH_LEN];
|
|
int i;
|
|
char *path;
|
|
size_t stringLen;
|
|
struct stat stbuf;
|
|
|
|
/*
|
|
* Create our own copy of path.
|
|
* I'd like to do a straight strdup here, but that caused problems
|
|
* for https.
|
|
*/
|
|
stringLen = strlen(inPath);
|
|
|
|
path = (char*) malloc(stringLen+1);
|
|
memcpy(path, inPath, stringLen);
|
|
path[stringLen] = '\0';
|
|
|
|
control = CMT_ControlConnect(mutex, sockFuncs);
|
|
if (control != NULL) {
|
|
return control;
|
|
}
|
|
/*
|
|
* We have to try to launch it now, so it better be a valid
|
|
* path.
|
|
*/
|
|
if (stat(path, &stbuf) == -1) {
|
|
goto loser;
|
|
}
|
|
/*
|
|
* Now we have to parse the path and launch the psm server.
|
|
*/
|
|
executable = strrchr(path, DIRECTORY_SEPARATOR);
|
|
if (executable != NULL) {
|
|
*executable = '\0';
|
|
executable ++;
|
|
newWorkingDir = path;
|
|
} else {
|
|
executable = path;
|
|
newWorkingDir = NULL;
|
|
}
|
|
if (getCurrWorkDir(oldWorkingDir, MAX_PATH_LEN) == NULL) {
|
|
goto loser;
|
|
}
|
|
setWorkingDir(newWorkingDir);
|
|
if (launch_psm(executable) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
setWorkingDir(oldWorkingDir);
|
|
/*
|
|
* Now try to connect to the psm server. We will try to connect
|
|
* a maximum of 30 times and then give up.
|
|
*/
|
|
#ifdef WIN32
|
|
for (i=0; i<30; i++) {
|
|
Sleep(1000);
|
|
control = CMT_ControlConnect(mutex, sockFuncs);
|
|
if (control != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
#elif defined XP_UNIX
|
|
i = 0;
|
|
while (i<1000) {
|
|
i += sleep(10);
|
|
control = CMT_ControlConnect(mutex, sockFuncs);
|
|
if (control != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
/*
|
|
* Figure out how to sleep for a while first
|
|
*/
|
|
for (i=0; i<30; i++) {
|
|
control = CMT_ControlConnect(mutex, sockFuncs);
|
|
if (control!= NULL) {
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if (control == NULL) {
|
|
goto loser;
|
|
}
|
|
if (path) {
|
|
free (path);
|
|
}
|
|
return control;
|
|
loser:
|
|
if (control != NULL) {
|
|
CMT_CloseControlConnection(control);
|
|
}
|
|
if (path) {
|
|
free(path);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PCMT_CONTROL CMT_ControlConnect(CMT_MUTEX *mutex, CMT_SocketFuncs *sockFuncs)
|
|
{
|
|
PCMT_CONTROL control = NULL;
|
|
CMTSocket sock=NULL;
|
|
SSMObscureObject * obscureObj = NULL;
|
|
#ifdef XP_UNIX
|
|
int unixSock = 1;
|
|
char path[20];
|
|
#else
|
|
int unixSock = 0;
|
|
char *path=NULL;
|
|
#endif
|
|
|
|
if (sockFuncs == NULL) {
|
|
return NULL;
|
|
}
|
|
#ifdef XP_UNIX
|
|
sprintf(path, "/tmp/.nsmc-%d", (int)geteuid());
|
|
#endif
|
|
|
|
sock = sockFuncs->socket(unixSock);
|
|
if (sock == NULL) {
|
|
LOG("Could not create a socket to connect to Control Connection.\n");
|
|
goto loser;
|
|
}
|
|
/* Connect to the psm process */
|
|
if (sockFuncs->connect(sock, CARTMAN_PORT, path)) {
|
|
LOG("Could not connect to Cartman\n");
|
|
goto loser;
|
|
}
|
|
|
|
#ifdef XP_UNIX
|
|
if (sockFuncs->verify(sock) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
#endif
|
|
|
|
LOG("Connected to Cartman\n");
|
|
|
|
/* Set up the protocol obfuscation */
|
|
if (!(obscureObj = InitClientObscureObject(sockFuncs, sock))) {
|
|
goto loser;
|
|
}
|
|
|
|
/* fill in the CMTControl struct */
|
|
control = (PCMT_CONTROL)calloc(sizeof(CMT_CONTROL), 1);
|
|
if (control == NULL ) {
|
|
goto loser;
|
|
}
|
|
control->sock = sock;
|
|
control->obscureObj = obscureObj;
|
|
if (mutex != NULL) {
|
|
control->mutex = (CMT_MUTEX*)calloc(sizeof(CMT_MUTEX),1);
|
|
if (control->mutex == NULL) {
|
|
goto loser;
|
|
}
|
|
*control->mutex = *mutex;
|
|
}
|
|
memcpy(&control->sockFuncs, sockFuncs, sizeof(CMT_SocketFuncs));
|
|
control->refCount = 1;
|
|
goto done;
|
|
|
|
loser:
|
|
if (control != NULL) {
|
|
free(control);
|
|
}
|
|
if (sock != NULL) {
|
|
sockFuncs->close(sock);
|
|
}
|
|
control = NULL;
|
|
|
|
done:
|
|
return control;
|
|
}
|
|
|
|
CMTStatus CMT_CloseControlConnection(PCMT_CONTROL control)
|
|
{
|
|
/* XXX Don't know what to do here yet */
|
|
if (control != NULL) {
|
|
CMInt32 refCount;
|
|
CMT_LOCK(control->mutex);
|
|
control->refCount--;
|
|
refCount = control->refCount;
|
|
CMT_UNLOCK(control->mutex);
|
|
if (refCount <= 0) {
|
|
if (control->mutex != NULL) {
|
|
free (control->mutex);
|
|
}
|
|
if (control->obscureObj) {
|
|
SSMObscure_Destroy(control->obscureObj);
|
|
}
|
|
control->sockFuncs.close(control->sock);
|
|
free(control);
|
|
}
|
|
}
|
|
|
|
return CMTSuccess;
|
|
}
|
|
|
|
CMTStatus CMT_Hello(PCMT_CONTROL control, CMUint32 version, char* profile,
|
|
char* profileDir)
|
|
{
|
|
CMTItem message;
|
|
PCMT_EVENT eventHandler;
|
|
CMBool doesUI;
|
|
HelloRequest request;
|
|
HelloReply reply;
|
|
|
|
/* Check the passed parameters */
|
|
if (!control) {
|
|
return CMTFailure;
|
|
}
|
|
if (!profile) {
|
|
return CMTFailure;
|
|
}
|
|
if (!profileDir) {
|
|
return CMTFailure;
|
|
}
|
|
|
|
/* Create the hello message */
|
|
eventHandler = CMT_GetEventHandler(control, SSM_UI_EVENT, 0);
|
|
doesUI = (eventHandler == NULL) ? CM_FALSE : CM_TRUE;
|
|
|
|
/* Setup the request struct */
|
|
request.version = version;
|
|
request.policy = 0; /* no more policy */
|
|
request.doesUI = doesUI;
|
|
request.profile = profile;
|
|
request.profileDir = profileDir;
|
|
|
|
message.type = SSM_REQUEST_MESSAGE | SSM_HELLO_MESSAGE;
|
|
|
|
if (CMT_EncodeMessage(HelloRequestTemplate, &message, &request) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Send the message and get the response */
|
|
if (CMT_SendMessage(control, &message) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_HELLO_MESSAGE)) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Decode the message */
|
|
if (CMT_DecodeMessage(HelloReplyTemplate, &reply, &message) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Successful response */
|
|
if (reply.result == 0) {
|
|
/* Save the nonce value */
|
|
control->sessionID = reply.sessionID;
|
|
control->protocolVersion = reply.version;
|
|
control->port = reply.httpPort;
|
|
control->nonce = reply.nonce;
|
|
control->policy = reply.policy;
|
|
control->serverStringVersion = reply.stringVersion;
|
|
|
|
/* XXX Free the messages */
|
|
return CMTSuccess;
|
|
}
|
|
loser:
|
|
/* XXX Free the messages */
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_PassAllPrefs(PCMT_CONTROL control, int num,
|
|
CMTSetPrefElement* list)
|
|
{
|
|
SetPrefListMessage request;
|
|
SingleNumMessage reply;
|
|
CMTItem message;
|
|
|
|
if ((control == NULL) || (list == NULL)) {
|
|
return CMTFailure;
|
|
}
|
|
|
|
/* pack the request */
|
|
request.length = num;
|
|
request.list = (SetPrefElement*)list;
|
|
|
|
if (CMT_EncodeMessage(SetPrefListMessageTemplate, &message, &request) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
message.type = SSM_REQUEST_MESSAGE | SSM_PREF_ACTION;
|
|
|
|
/* send the message */
|
|
if (CMT_SendMessage(control, &message) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_PREF_ACTION)) {
|
|
goto loser;
|
|
}
|
|
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &reply, &message) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* don't really need to check the return value */
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
}
|
|
|
|
char* CMT_GetServerStringVersion(PCMT_CONTROL control)
|
|
{
|
|
if (control == NULL) {
|
|
return NULL;
|
|
}
|
|
return control->serverStringVersion;
|
|
}
|