Mercurial > pidgin.yaz
view libpurple/protocols/zephyr/ZParseNot.c @ 29871:6d2ba42595fe
oscar: Fix a race condition that leads to a crash.
With SSL enabled, if we start connecting and something calls
purple_account_disconnect between when an SSL flap connection is started
and when the connection is actually established, it isn't properly
cleaned up (and we try to close the flap), which leads to free-after-use.
You can simulate this by adding a timeout-triggered disconnect to the
end of oscar_connect_to_bos.
[02/22/10 17:11:51] <libpurple/oscar> Destroying oscar connection of type 0x0002. Disconnect reason is 0
[02/22/10 17:11:51] <libpurple/oscar> Disconnected. Code is 0x0000 and msg is
(hiicq:17126): GLib-WARNING **: giounix.c:400Error while getting flags for FD: Bad file descriptor (9)
[02/22/10 17:11:51] <libpurple/oscar> Scheduling destruction of FLAP connection of type 0x0002
[02/22/10 17:11:51] <libpurple/oscar> Signed off.
...
[02/22/10 17:11:51] <libpurple/oscar> Destroying oscar connection of type 0x7261. Disconnect reason is 1668179315
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Mon, 22 Feb 2010 17:53:38 +0000 |
parents | 5fe8042783c1 |
children | a8cc50c2279f |
line wrap: on
line source
/* This file is part of the Project Athena Zephyr Notification System. * It contains source for the ZParseNotice function. * * Created by: Robert French * * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file * "mit-copyright.h". */ #include "internal.h" /* Assume that strlen is efficient on this machine... */ #define next_field(ptr) ptr += strlen (ptr) + 1 #if defined (__GNUC__) && defined (__vax__) #undef next_field static __inline__ char * Istrend (char *str) { /* * This should be faster on VAX models outside the 2 series. Don't * use it if you are using MicroVAX 2 servers. If you are using a * VS2 server, use something like * #define next_field(ptr) while(*ptr++) * instead of this code. * * This requires use of GCC to get the optimized code, but * everybody uses GCC, don't they? :-) */ register char *str2 asm ("r1"); /* Assumes that no field is longer than 64K.... */ asm ("locc $0,$65535,(%1)" : "=r" (str2) : "r" (str) : "r0"); return str2; } #define next_field(ptr) ptr = Istrend (ptr) + 1 #endif #ifdef mips #undef next_field /* * The compiler doesn't optimize this macro as well as it does the * following function. */ #define next_fieldXXX(ptr) do{register unsigned c1,c2;c1= *ptr; \ while((ptr++,c2= *ptr,c1)&&(ptr++,c1= *ptr,c2));}while(0) static char *next_field_1 (s) char *s; { /* * Calling overhead is still present, but this routine is faster * than strlen, and doesn't bother with some of the other math * that we'd just have to undo later anyways. */ register unsigned c1 = *s, c2; while (1) { s++; c2 = *s; if (c1 == 0) break; s++; c1 = *s; if (c2 == 0) break; s++; c2 = *s; if (c1 == 0) break; s++; c1 = *s; if (c2 == 0) break; } return s; } #define next_field(ptr) ptr=next_field_1(ptr) #endif Code_t ZParseNotice(buffer, len, notice) char *buffer; int len; ZNotice_t *notice; { char *ptr, *end; unsigned long temp; int maj, numfields, i; #ifdef __LINE__ int lineno; /* Note: This definition of BAD eliminates lint and compiler * complains about the "while (0)", but require that the macro not * be used as the "then" part of an "if" statement that also has * an "else" clause. */ #define BAD_PACKET {lineno=__LINE__;goto badpkt;} /* This one gets lint/compiler complaints. */ /*#define BAD do{lineno=__LINE__;goto badpkt;}while(0)*/ #else #define BAD_PACKET goto badpkt #endif (void) memset((char *)notice, 0, sizeof(ZNotice_t)); ptr = buffer; end = buffer+len; notice->z_packet = buffer; notice->z_version = ptr; if (strncmp(ptr, ZVERSIONHDR, sizeof(ZVERSIONHDR) - 1)) return (ZERR_VERS); ptr += sizeof(ZVERSIONHDR) - 1; if (!*ptr) { #ifdef Z_DEBUG Z_debug ("ZParseNotice: null version string"); #endif return ZERR_BADPKT; } maj = atoi(ptr); if (maj != ZVERSIONMAJOR) return (ZERR_VERS); next_field (ptr); if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) BAD_PACKET; numfields = temp; next_field (ptr); /*XXX 3 */ numfields -= 2; /* numfields, version, and checksum */ if (numfields < 0) { #ifdef __LINE__ lineno = __LINE__; badpkt: #ifdef Z_DEBUG Z_debug ("ZParseNotice: bad packet from %s/%d (line %d)", inet_ntoa (notice->z_uid.zuid_addr.s_addr), notice->z_port, lineno); #endif #else badpkt: #ifdef Z_DEBUG Z_debug ("ZParseNotice: bad packet from %s/%d", inet_ntoa (notice->z_uid.zuid_addr.s_addr), notice->z_port); #endif #endif return ZERR_BADPKT; } if (numfields) { if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) BAD_PACKET; notice->z_kind = temp; numfields--; next_field (ptr); } else BAD_PACKET; if (numfields) { if (ZReadAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid, sizeof(ZUnique_Id_t)) == ZERR_BADFIELD) BAD_PACKET; notice->z_time.tv_sec = ntohl((unsigned long) notice->z_uid.tv.tv_sec); notice->z_time.tv_usec = ntohl((unsigned long) notice->z_uid.tv.tv_usec); numfields--; next_field (ptr); } else BAD_PACKET; if (numfields) { if (ZReadAscii16(ptr, end-ptr, ¬ice->z_port) == ZERR_BADFIELD) BAD_PACKET; notice->z_port = htons(notice->z_port); numfields--; next_field (ptr); } else BAD_PACKET; if (numfields) { if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) BAD_PACKET; notice->z_auth = temp; numfields--; next_field (ptr); } else BAD_PACKET; notice->z_checked_auth = ZAUTH_UNSET; if (numfields) { if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) BAD_PACKET; notice->z_authent_len = temp; numfields--; next_field (ptr); } else BAD_PACKET; if (numfields) { notice->z_ascii_authent = ptr; numfields--; next_field (ptr); } else BAD_PACKET; if (numfields) { notice->z_class = ptr; numfields--; next_field (ptr); } else notice->z_class = ""; if (numfields) { notice->z_class_inst = ptr; numfields--; next_field (ptr); } else notice->z_class_inst = ""; if (numfields) { notice->z_opcode = ptr; numfields--; next_field (ptr); } else notice->z_opcode = ""; if (numfields) { notice->z_sender = ptr; numfields--; next_field (ptr); } else notice->z_sender = ""; if (numfields) { notice->z_recipient = ptr; numfields--; next_field (ptr); } else notice->z_recipient = ""; if (numfields) { notice->z_default_format = ptr; numfields--; next_field (ptr); } else notice->z_default_format = ""; /*XXX*/ if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) BAD_PACKET; notice->z_checksum = temp; numfields--; next_field (ptr); if (numfields) { notice->z_multinotice = ptr; numfields--; next_field (ptr); } else notice->z_multinotice = ""; if (numfields) { if (ZReadAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid, sizeof(ZUnique_Id_t)) == ZERR_BADFIELD) BAD_PACKET; notice->z_time.tv_sec = ntohl((unsigned long) notice->z_multiuid.tv.tv_sec); notice->z_time.tv_usec = ntohl((unsigned long) notice->z_multiuid.tv.tv_usec); numfields--; next_field (ptr); } else notice->z_multiuid = notice->z_uid; for (i=0;i<Z_MAXOTHERFIELDS && numfields;i++,numfields--) { notice->z_other_fields[i] = ptr; next_field (ptr); } notice->z_num_other_fields = i; for (i=0;i<numfields;i++) next_field (ptr); notice->z_message = (void *)ptr; notice->z_message_len = len-(ptr-buffer); return (ZERR_NONE); }