From 899a91d4109e0e49e068a35aa34cb8cd7a07067f Mon Sep 17 00:00:00 2001 From: achmizs Date: Wed, 23 Dec 2015 19:37:00 -0500 Subject: [PATCH] Fix bad access bugs (hopefully) In some callbacks, NSData objects to be passed to IRCClientSession's event handlers would be nil (if e.g. a user parted a channel without giving a reason). Those object references would then be sent messages. This is bad. Instead, an NSData object is always allocated now, even for blank reasons/messages/notices/etc. This object simply contains a single null byte (i.e. it holds an empty, null-terminated C string). --- IRCClient/IRCClientSession.h | 15 ++++ IRCClient/IRCClientSession.m | 135 ++++++++++++++++++++++++++--------- 2 files changed, 118 insertions(+), 32 deletions(-) diff --git a/IRCClient/IRCClientSession.h b/IRCClient/IRCClientSession.h index 38f7f5c..afe410a 100644 --- a/IRCClient/IRCClientSession.h +++ b/IRCClient/IRCClientSession.h @@ -133,6 +133,21 @@ #pragma mark - Class methods /***************************/ +/** Returns a dictionary of IRC numeric codes. + + The dictionary contains entries for all known IRC numeric codes (as keys). + (The list is taken from https://www.alien.net.au/irc/irc2numerics.html .) + + The value for each key is an NSArray with the known numeric reply names for + which the numeric code is used. + + Note that there is no gaurantee whatsoever that any given numeric reply + name will, in fact, describe the contents of the message; most IRC numeric + messages have implementation-specific uses. See the various RFCs, and other + info sources, for details. + */ ++(NSDictionary *)IRCNumericCodes; + /** Set the nickname, username, and realname for the session. Returns 1 if successfully set, 0 otherwise. diff --git a/IRCClient/IRCClientSession.m b/IRCClient/IRCClientSession.m index c374caf..111a87f 100644 --- a/IRCClient/IRCClientSession.m +++ b/IRCClient/IRCClientSession.m @@ -50,6 +50,8 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha #pragma mark - IRCClientSession private category declaration +static NSDictionary* ircNumericCodeList; + @interface IRCClientSession() { irc_callbacks_t _callbacks; @@ -61,6 +63,8 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha @property (readwrite) NSMutableDictionary *channels; ++(void)loadNumericCodes; + @end #pragma mark - IRCClientSession class implementation @@ -162,6 +166,30 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha irc_destroy_session(_irc_session); } ++(NSDictionary *)IRCNumericCodes +{ + if(ircNumericCodeList == nil) + { + [IRCClientSession loadNumericCodes]; + } + + return ircNumericCodeList; +} + ++(void)loadNumericCodes +{ + NSString* numericCodeListPath = [[NSBundle mainBundle] pathForResource:@"IRC_Numerics" ofType:@"plist"]; + ircNumericCodeList = [NSDictionary dictionaryWithContentsOfFile:numericCodeListPath]; + if(ircNumericCodeList) + { + NSLog(@"IRC numeric codes list loaded successfully.\n"); + } + else + { + NSLog(@"Could not load IRC numeric codes list!\n"); + } +} + - (int)connect; { return irc_connect(_irc_session, _server.UTF8String, (unsigned short) _port, (_password.length > 0 ? _password.SA_terminatedCString : NULL), _nickname.UTF8String, _username.UTF8String, _realname.UTF8String); @@ -399,13 +427,6 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha [_delegate privateMessageReceived:messageString fromUser:nick]; } -- (void)noticeSent:(NSData *)notice toChannel:(NSData *)channelName byUser:(NSString *)nick -{ - IRCClientChannel *channel = _channels[channelName]; - - [channel noticeSent:notice byUser:nick]; -} - - (void)privateNoticeReceived:(NSData *)notice fromUser:(NSString *)nick { NSString* noticeString = [NSString stringWithCString:notice.SA_terminatedCString encoding:_encoding]; @@ -413,9 +434,16 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha [_delegate privateNoticeReceived:noticeString fromUser:nick]; } +- (void)noticeSent:(NSData *)notice toChannel:(NSData *)channelName byUser:(NSString *)nick +{ + IRCClientChannel *channel = _channels[channelName]; + + [channel noticeSent:notice byUser:nick]; +} + - (void)invitedToChannel:(NSData *)channelName by:(NSString *)nick { - [_delegate invitedToChannel:channelName by:nick]; + [_delegate invitedToChannel:channelName.SA_dataWithTerminatedCString by:nick]; } - (void)CTCPRequestReceived:(NSData *)request fromUser:(NSString *)nick @@ -429,15 +457,15 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha } else if (!strcmp (the_request, "VERSION")) { - irc_cmd_ctcp_reply (_irc_session, the_nick, [NSString stringWithFormat:@"VERSION %@", _version].UTF8String); + irc_cmd_ctcp_reply (_irc_session, the_nick, [[NSString stringWithFormat:@"VERSION %@", _version] cStringUsingEncoding:_encoding]); } else if (!strcmp (the_request, "FINGER")) { - irc_cmd_ctcp_reply (_irc_session, the_nick, [NSString stringWithFormat:@"FINGER %@ (%@) Idle 0 seconds", _username, _realname].UTF8String); + irc_cmd_ctcp_reply (_irc_session, the_nick, [[NSString stringWithFormat:@"FINGER %@ (%@) Idle 0 seconds", _username, _realname] cStringUsingEncoding:_encoding]); } else if (!strcmp (the_request, "TIME")) { - irc_cmd_ctcp_reply(_irc_session, the_nick, [[NSDate dateWithTimeIntervalSinceNow:0] descriptionWithCalendarFormat:@"TIME %a %b %e %H:%M:%S %Z %Y" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]].UTF8String); + irc_cmd_ctcp_reply(_irc_session, the_nick, [[[NSDate dateWithTimeIntervalSinceNow:0] descriptionWithCalendarFormat:@"TIME %a %b %e %H:%M:%S %Z %Y" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]] cStringUsingEncoding:_encoding]); } else { @@ -449,7 +477,10 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha char* request_type = strtok(request_string, " "); char* request_body = strtok(NULL, " " ); - [_delegate CTCPRequestReceived:[NSData dataWithBytes:request_body length:strlen(request_body) + 1] ofType:[NSData dataWithBytes:request_type length:strlen(request_type) + 1] fromUser:nick]; + NSData* requestTypeData = [NSData dataWithBytes:request_body length:strlen(request_body) + 1]; + NSData* requestBodyData = [NSData dataWithBytes:request_type length:strlen(request_type) + 1]; + + [_delegate CTCPRequestReceived:requestBodyData.SA_dataWithTerminatedCString ofType:requestTypeData.SA_dataWithTerminatedCString fromUser:nick]; free(request_string); } @@ -458,7 +489,7 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha - (void)CTCPReplyReceived:(NSData *)reply fromUser:(NSString *)nick { - [_delegate CTCPReplyReceived:reply fromUser:nick]; + [_delegate CTCPReplyReceived:reply.SA_dataWithTerminatedCString fromUser:nick]; } - (void)CTCPActionPerformed:(NSData *)action byUser:(NSString *)nick atTarget:(NSData *)target @@ -480,7 +511,7 @@ static void onNumericEvent(irc_session_t *session, unsigned int event, const cha - (void)unknownEventReceived:(NSData *)event from:(NSString *)origin params:(NSArray *)params { - [_delegate unknownEventReceived:event from:origin params:params]; + [_delegate unknownEventReceived:event.SA_dataWithTerminatedCString from:origin params:params]; } -(void)numericEventReceived:(NSUInteger)event from:(NSString *)origin params:(NSArray *)params @@ -577,12 +608,16 @@ static void onNick(irc_session_t *session, const char *event, const char *origin static void onQuit(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count) { IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); - NSString *nick = @(origin); + NSData *reason = nil; if(count > 0) { - reason = [[NSData alloc] initWithBytes:params[0] length:strlen(params[0]) + 1]; + reason = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; + } + else + { + reason = [NSData dataWithBytes:"\0" length:1]; } [clientSession userQuit:nick withReason:reason]; @@ -621,12 +656,16 @@ static void onPartChannel(irc_session_t *session, const char *event, const char IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *nick = @(origin); NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; + NSData *reason = nil; - if (count > 1) { reason = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + reason = [NSData dataWithBytes:"\0" length:1]; + } [clientSession userParted:nick channel:channelName withReason:reason]; } @@ -650,12 +689,16 @@ static void onMode(irc_session_t *session, const char *event, const char *origin NSString *nick = @(origin); NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; NSString *mode = @(params[1]); + NSString *modeParams = nil; - if (count > 2) { modeParams = @(params[2]); } + else + { + modeParams = @""; + } [clientSession modeSet:mode withParams:modeParams forChannel:channelName by:nick]; } @@ -697,6 +740,10 @@ static void onTopic(irc_session_t *session, const char *event, const char *origi { topic = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + topic = [NSData dataWithBytes:"\0" length:1]; + } [clientSession topicSet:topic forChannel:channelName by:nick]; } @@ -716,18 +763,22 @@ static void onKick(irc_session_t *session, const char *event, const char *origin IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *byNick = @(origin); NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; + NSString *nick = nil; - NSData *reason = nil; - if (count > 1) { nick = @(params[1]); } + NSData *reason = nil; if (count > 2) { reason = [NSData dataWithBytes:params[2] length:strlen(params[2]) + 1]; } + else + { + reason = [NSData dataWithBytes:"\0" length:1]; + } [clientSession userKicked:nick fromChannel:channelName by:byNick withReason:reason]; } @@ -747,12 +798,16 @@ static void onChannelPrvmsg(irc_session_t *session, const char *event, const cha IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *nick = @(origin); NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; - NSData *message = nil; + NSData *message = nil; if (count > 1) { message = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + message = [NSData dataWithBytes:"\0" length:1]; + } [clientSession messageSent:message toChannel:channelName byUser:nick]; } @@ -770,12 +825,16 @@ static void onPrivmsg(irc_session_t *session, const char *event, const char *ori { IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *nick = @(origin); + NSData *message = nil; - if (count > 1) { message = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + message = [NSData dataWithBytes:"\0" length:1]; + } [clientSession privateMessageReceived:message fromUser:nick]; } @@ -797,12 +856,16 @@ static void onNotice(irc_session_t *session, const char *event, const char *orig { IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *nick = @(origin); - NSData *notice = nil; + NSData *notice = nil; if (count > 1) { notice = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + notice = [NSData dataWithBytes:"\0" length:1]; + } [clientSession privateNoticeReceived:notice fromUser:nick]; } @@ -825,12 +888,16 @@ static void onChannelNotice(irc_session_t *session, const char *event, const cha IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); NSString *nick = @(origin); NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0]) + 1]; - NSData *notice = nil; + NSData *notice = nil; if (count > 1) { notice = [NSData dataWithBytes:params[1] length:strlen(params[1]) + 1]; } + else + { + notice = [NSData dataWithBytes:"\0" length:1]; + } [clientSession noticeSent:notice toChannel:channelName byUser:nick]; } @@ -925,18 +992,21 @@ static void onCtcpAction(irc_session_t *session, const char *event, const char * static void onUnknownEvent(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count) { IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session); - NSData *eventString = [NSData dataWithBytes:event length:strlen(event) + 1]; - NSString *sender = nil; - + NSData *eventData = [NSData dataWithBytes:event length:strlen(event) + 1]; + + NSString *originString = nil; if (origin != NULL) - sender = @(origin); + { + originString = @(origin); + } NSMutableArray *paramsArray = [[NSMutableArray alloc] init]; - for (unsigned int i = 0; i < count; i++) + { [paramsArray addObject:[NSData dataWithBytes:params[i] length:strlen(params[i]) + 1]]; + } - [clientSession unknownEventReceived:eventString from:sender params:[paramsArray copy]]; + [clientSession unknownEventReceived:eventData from:originString params:paramsArray]; } /*! @@ -953,9 +1023,10 @@ static void onNumericEvent(irc_session_t * session, unsigned int event, const ch NSString *sender = @(origin); NSMutableArray *paramsArray = [[NSMutableArray alloc] init]; - for (unsigned int i = 0; i < count; i++) + { [paramsArray addObject:[NSData dataWithBytes:params[i] length:strlen(params[i]) + 1]]; + } - [clientSession numericEventReceived:eventNumber from:sender params:[paramsArray copy]]; + [clientSession numericEventReceived:eventNumber from:sender params:paramsArray]; }