/* -*- 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 #include #include #else #ifdef XP_MAC #include "macsocket.h" #else /* Windows */ #include #include #endif #endif #include "cmtcmn.h" #include "cmtutils.h" #include "newproto.h" #include /* Local defines */ #if 0 #define PSM_WAIT_BEFORE_SLEEP (CM_TicksPerSecond() * 60) #define PSM_SPINTIME PSM_WAIT_BEFORE_SLEEP #define PSM_KEEP_CONNECTION_ALIVE (PSM_WAIT_BEFORE_SLEEP * 900) #endif /* If you want to dump the messages sent between the plug-in and the PSM * server, then remove the comment for the appropriate define. */ #if 0 #define PRINT_SEND_MESSAGES #define PRINT_RECEIVE_MESSAGES #endif #ifdef PRINT_SEND_MESSAGES #ifndef DEBUG_MESSAGES #define DEBUG_MESSAGES #endif /*DEBUG_MESSAGES*/ #endif /*PRINT_SEND_MESSAGES*/ #ifdef PRINT_RECEIVE_MESSAGES #ifndef DEBUG_MESSAGES #define DEBUG_MESSAGES #endif /*DEBUG_MESSAGES*/ #endif /*PRINT_RECEIVE_MESSAGES*/ #ifdef DEBUG_MESSAGES #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 CMUint32 cmt_Strlen(char *str) { CMUint32 len = strlen(str); return sizeof(CMInt32) + (((len + 3)/4)*4); } CMUint32 cmt_Bloblen(CMTItem *blob) { return sizeof(CMInt32) + (((blob->len +3)/4)*4); } char * cmt_PackString(char *buf, char *str) { CMUint32 len = strlen(str); CMUint32 networkLen = htonl(len); CMUint32 padlen = ((len + 3)/4)*4; memcpy(buf, &networkLen, sizeof(CMUint32)); memcpy(buf + sizeof(CMUint32), str, len); memset(buf + sizeof(CMUint32) + len, 0, padlen - len); return buf+sizeof(CMUint32)+padlen; } char * cmt_PackBlob(char *buf, CMTItem *blob) { CMUint32 len = blob->len; CMUint32 networkLen = htonl(len); CMUint32 padlen = (((blob->len + 3)/4)*4); *((CMUint32*)buf) = networkLen; memcpy(buf + sizeof(CMUint32), blob->data, len); memset(buf + sizeof(CMUint32) + len, 0, padlen - len); return buf + sizeof(CMUint32) + padlen; } char * cmt_UnpackString(char *buf, char **str) { char *p = NULL; CMUint32 len, padlen; /* Get the string length */ len = ntohl(*(CMUint32*)buf); /* Get the padded length */ padlen = ((len + 3)/4)*4; /* Allocate the string and copy the data */ p = (char *) malloc(len + 1); if (!p) { goto loser; } /* Copy the data and NULL terminate */ memcpy(p, buf+sizeof(CMUint32), len); p[len] = 0; *str = p; return buf+sizeof(CMUint32)+padlen; loser: *str = NULL; if (p) { free(p); } return buf+sizeof(CMUint32)+padlen; } char * cmt_UnpackBlob(char *buf, CMTItem **blob) { CMTItem *p = NULL; CMUint32 len, padlen; /* Get the blob length */ len = ntohl(*(CMUint32*)buf); /* Get the padded length */ padlen = ((len + 3)/4)*4; /* Allocate the CMTItem for the blob */ p = (CMTItem*)malloc(sizeof(CMTItem)); if (!p) { goto loser; } p->len = len; p->data = (unsigned char *) malloc(len); if (!p->data) { goto loser; } /* Copy that data across */ memcpy(p->data, buf+sizeof(CMUint32), len); *blob = p; return buf+sizeof(CMUint32)+padlen; loser: *blob = NULL; CMT_FreeMessage(p); return buf+sizeof(CMUint32)+padlen; } #ifdef DEBUG_MESSAGES void prettyPrintMessage(CMTItem *msg) { int numLines = ((msg->len+7)/8); char curBuffer[9], *cursor, string[2], hexVal[8]; char hexArray[25]; int i, j, numToCopy; /*Try printing out 8 bytes at a time. */ LOG("\n**********************************************************\n"); LOG("About to pretty Print Message\n\n"); curBuffer[9] = '\0'; hexArray[24] = '\0'; hexVal[2] = '\0'; string[1] = '\0'; LOG("Header Info\n"); LOG("Message Type: "); sprintf(hexArray, "%lx\n", msg->type); LOG(hexArray); LOG("Message Length: "); sprintf (hexArray, "%ld\n\n", msg->len); LOG(hexArray); LOG("Body of Message\n"); for (i=0, cursor=msg->data; ilen - (unsigned int)((unsigned long)cursor-(unsigned long)msg->data)) < 8) ? msg->len - (unsigned int)((unsigned long)cursor-(unsigned long)msg->data) : 8; memcpy(curBuffer, cursor, 8); for (j=0;jmutex); /* Try to send pending random data */ if (message->type != (SSM_REQUEST_MESSAGE | SSM_HELLO_MESSAGE)) { /* If we've already said hello, then flush random data just before sending the request. */ status = CMT_FlushPendingRandomData(control); if (status != CMTSuccess) goto loser; } status = CMT_TransmitMessage(control, message); if (status != CMTSuccess) { goto loser; } /* We have to deal with other types of data on the socket and */ /* handle them accordingly */ while (!done) { status = CMT_ReceiveMessage(control, message); if (status != CMTSuccess) { goto loser; } msgCategory = (message->type & SSM_CATEGORY_MASK); switch (msgCategory) { case SSM_REPLY_OK_MESSAGE: done = CM_TRUE; break; case SSM_REPLY_ERR_MESSAGE: done = CM_TRUE; break; case SSM_EVENT_MESSAGE: CMT_DispatchEvent(control, message); break; /* XXX FIX THIS!!! For the moment I'm ignoring all other types */ default: break; } } /* Release the control connection lock */ CMT_UNLOCK(control->mutex); return CMTSuccess; loser: /* Release the control connection lock */ CMT_UNLOCK(control->mutex); return CMTFailure; } CMTStatus CMT_TransmitMessage(PCMT_CONTROL control, CMTItem * message) { CMTMessageHeader header; CMUint32 sent, rv; /* Set up the message header */ header.type = htonl(message->type); header.len = htonl(message->len); /* Obscure the message header */ rv = SSMObscure_Send(control->obscureObj, &header, sizeof(CMTMessageHeader)); if (rv != 0) { goto loser; } /* Send the message header */ sent = CMT_WriteThisMany(control, control->sock, (void *)&header, sizeof(CMTMessageHeader)); if (sent != sizeof(CMTMessageHeader)) { goto loser; } /* Obscure the message body */ rv = SSMObscure_Send(control->obscureObj, message->data, message->len); if (rv != 0) { goto loser; } /* Send the message body */ sent = CMT_WriteThisMany(control, control->sock, (void *)message->data, message->len); if (sent != message->len) { goto loser; } /* Free the buffer */ free(message->data); message->data = NULL; return CMTSuccess; loser: return CMTFailure; } CMTStatus CMT_ReceiveMessage(PCMT_CONTROL control, CMTItem * response) { CMTMessageHeader header; CMUint32 read, rv; /* Get the obscured message header */ read = CMT_ReadThisMany(control, control->sock, (void *)&header, sizeof(CMTMessageHeader)); if (read != sizeof(CMTMessageHeader)) { goto loser; } /* Unobscure the message header */ rv = SSMObscure_Recv(control->obscureObj, &header, sizeof(CMTMessageHeader)); if (rv != 0) { goto loser; } response->type = ntohl(header.type); response->len = ntohl(header.len); response->data = (unsigned char *) malloc(response->len); if (response->data == NULL) { goto loser; } read = CMT_ReadThisMany(control, control->sock, (void *)(response->data), response->len); if (read != response->len) { goto loser; } /* Unobscure the message body */ rv = SSMObscure_Recv(control->obscureObj, response->data, response->len); if (rv != 0) { goto loser; } #ifdef PRINT_RECEIVE_MESSAGES LOG("About to print message received from PSM.\n"); prettyPrintMessage(response); #endif /*PRINT_RECEIVE_MESSAGES*/ return CMTSuccess; loser: if (response->data) { free(response->data); } return CMTFailure; } CMUint32 CMT_ReadThisMany(PCMT_CONTROL control, CMTSocket sock, void * buffer, CMUint32 thisMany) { CMUint32 total = 0; while (total < thisMany) { int got; got = control->sockFuncs.recv(sock, (void*)((char*)buffer + total), thisMany-total); if (got < 0 ) { break; } total += got; } return total; } CMUint32 CMT_WriteThisMany(PCMT_CONTROL control, CMTSocket sock, void * buffer, CMUint32 thisMany) { CMUint32 total = 0; while (total < thisMany) { CMUint32 got; got = control->sockFuncs.send(sock, (void*)((char*)buffer+total), thisMany-total); if (got < 0) { break; } total += got; } return total; } CMTItem* CMT_ConstructMessage(CMUint32 type, CMUint32 length) { CMTItem * p; p = (CMTItem*)malloc(sizeof(CMTItem)); if (!p) { goto loser; } p->type = type; p->len = length; p->data = (unsigned char *) malloc(length); if (!p->data) { goto loser; } return p; loser: CMT_FreeMessage(p); return NULL; } void CMT_FreeMessage(CMTItem * p) { if (p != NULL) { if (p->data != NULL) { free(p->data); } free(p); } } CMTStatus CMT_AddDataConnection(PCMT_CONTROL control, CMTSocket sock, CMUint32 connectionID) { PCMT_DATA ptr; /* This is the first connection */ if (control->cmtDataConnections == NULL) { control->cmtDataConnections = ptr = (PCMT_DATA)calloc(sizeof(CMT_DATA), 1); if (!ptr) { goto loser; } } else { /* Position at the last entry */ for (ptr = control->cmtDataConnections; (ptr != NULL && ptr->next != NULL); ptr = ptr->next); ptr->next = (PCMT_DATA)calloc(sizeof(CMT_DATA), 1); if (!ptr->next) { goto loser; } /* Fix up the pointers */ ptr->next->previous = ptr; ptr = ptr->next; } /* Fill in the data */ ptr->sock = sock; ptr->connectionID = connectionID; return CMTSuccess; loser: return CMTFailure; } int CMT_DestroyDataConnection(PCMT_CONTROL control, CMTSocket sock) { PCMT_DATA ptr, pptr = NULL; int rv=CMTSuccess; control->sockFuncs.close(sock); for (ptr = control->cmtDataConnections; ptr != NULL; pptr = ptr, ptr = ptr->next) { if (ptr->sock == sock) { if (pptr == NULL) { /* node is at head */ control->cmtDataConnections = ptr->next; if (ptr->priv != NULL) ptr->priv->dest(ptr->priv); free(ptr); return rv; } /* node is elsewhere */ pptr->next = ptr->next; if (ptr->priv != NULL) ptr->priv->dest(ptr->priv); free(ptr); return rv; } } return rv; } CMTStatus CMT_CloseDataConnection(PCMT_CONTROL control, CMUint32 connectionID) { /* PCMT_DATA ptr, pptr = NULL; */ CMTSocket sock; /* int rv;*/ /* Get the socket for this connection */ if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) { goto loser; } /* Free data connection associated with this socket */ if (CMT_DestroyDataConnection(control, sock) == CMTFailure) { goto loser; } return CMTSuccess; loser: return CMTFailure; } CMTStatus CMT_GetDataConnectionID(PCMT_CONTROL control, CMTSocket sock, CMUint32 * connectionID) { PCMT_DATA ptr; for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) { if (ptr->sock == sock) { *connectionID = ptr->connectionID; return CMTSuccess; } } return CMTFailure; } CMTStatus CMT_GetDataSocket(PCMT_CONTROL control, CMUint32 connectionID, CMTSocket * sock) { PCMT_DATA ptr; for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) { if (ptr->connectionID == connectionID) { *sock = ptr->sock; return CMTSuccess; } } return CMTFailure; } CMTStatus CMT_SetPrivate(PCMT_CONTROL control, CMUint32 connectionID, CMTPrivate *cmtpriv) { PCMT_DATA ptr; for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) { if (ptr->connectionID == connectionID) { ptr->priv = cmtpriv; return CMTSuccess; } } return CMTFailure; } CMTPrivate *CMT_GetPrivate(PCMT_CONTROL control, CMUint32 connectionID) { PCMT_DATA ptr; for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) { if (ptr->connectionID == connectionID) { return ptr->priv; } } return NULL; } void CMT_FreeItem(CMTItem *p) { CMT_FreeMessage(p); } CMTItem CMT_CopyPtrToItem(void* p) { CMTItem value = {0, NULL, 0}; if (!p) { return value; } value.len = sizeof(p); value.data = (unsigned char *) malloc(value.len); memcpy(value.data, &p, value.len); return value; } void * CMT_CopyItemToPtr(CMTItem value) { void * p = NULL; if (value.len == sizeof(void*)) { memcpy(&p, value.data, value.len); } return p; } CMTStatus CMT_ReferenceControlConnection(PCMT_CONTROL control) { CMT_LOCK(control->mutex); control->refCount++; CMT_UNLOCK(control->mutex); return CMTSuccess; } void CMT_LockConnection(PCMT_CONTROL control) { CMT_LOCK(control->mutex); } void CMT_UnlockConnection(PCMT_CONTROL control) { CMT_UNLOCK(control->mutex); }