On Wed, Sep 23, 2009 at 12:53:35AM +0200, Mark Edgar wrote:
* Fix buffer overrun when using strncpy()
It's really sad to see code using strncpy.
* Use startswith() macro instead strncmp()
Macros don't go over so well around here, but I'm in favor of that one (even if as a utility function rather than a macro).
* Use const char * where appropriate
const char* tends not to go over so well around here.
* Use size_t instead of unsigned int in readl().
We also tend not to use *_t integer types types in favor of int and uint.
I'll take this opportunity to re-submit my ages-old modifications of sic (which push the line count to 251). Incidentally, what's with all of the (void) casts of function calls lately? Have we really resorted to that level of GNU-style hair brained pedantry?
-- Kris Maglione The best way to predict the future is to invent it. --Alan Kay
/* ? 2005-2007 Anselm R. Garbe <garbeam at gmail dot com> * ? 2007 Kris Maglione <fbsdae...@gmail.com> * ? 2005 Nico Golde <nico at ngolde dot de> * See LICENSE file for license details. */ #include <ctype.h> #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #define nil ((void*)0) typedef unsigned short ushort; #define PINGTIMEOUT 300 static char* host = "irc.oftc.net"; static ushort port = 6667; static char* password; static char nick[32]; static char bufin[4096]; static char bufout[4096]; static char channel[256]; static time_t trespond; static FILE *srv; #define va_buf(buf, fmt) {\ va_list ap; \ \ va_start(ap, fmt); \ vsnprintf(buf, sizeof buf, fmt, ap); \ va_end(ap); \ } #include "util.c" static void pout(char *channel, char *fmt, ...) { static char timestr[18]; time_t t; va_buf(bufout, fmt); t = time(nil); strftime(timestr, sizeof timestr, "%D %R", localtime(&t)); fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout); } static void sout(char *fmt, ...) { va_buf(bufout, fmt); fprintf(srv, "%s\r\n", bufout); } static void privmsg(char *channel, char *msg) { if(channel[0] == '\0') { pout("", "No channel to send to"); return; } pout(channel, "<%s> %s", nick, msg); sout("PRIVMSG %s :%s", channel, msg); } static void parsein(char *msg) { char *p; char c; if(msg[0] == '\0') return; msg = ctok(&msg, '\n'); if(msg[0] != ':') { privmsg(channel, msg); return; } c = *++msg; if(!c || !isspace(msg[1])) sout("%s", msg); else { if(msg[1]) msg += 2; switch(c) { case 'j': sout("JOIN %s", msg); if(channel[0] == '\0') strlcpy(channel, msg, sizeof channel); break; case 'l': p = tok(&msg); if(!*p) p = channel; if(!*msg) msg = "sic - 250 LOC are too much!"; sout("PART %s :%s", p, msg); break; case 'm': p = tok(&msg); privmsg(p, msg); break; case 's': strlcpy(channel, msg, sizeof channel); break; default: sout("%c %s", c, msg); break; } } } static void parsesrv(char *msg) { char *cmd, *p, *usr, *txt; usr = host; if(!msg || !*msg) return; if(msg[0] == ':') { msg++; p = tok(&msg); if(!*msg) return; usr = ctok(&p, '!'); } txt = ctok(&msg, '\r'); msg = ctok(&txt, ':'); cmd = tok(&msg); if(!strcmp("PONG", cmd)) return; if(!strcmp("PRIVMSG", cmd)) pout(msg, "<%s> %s", usr, txt); else if(!strcmp("PING", cmd)) sout("PONG %s", txt); else { pout(usr, ">< %s: %s", cmd, txt); if(!strcmp("NICK", cmd) && !strcmp(usr, nick)) strlcpy(nick, txt, sizeof nick); } } int main(int argc, char *argv[]) { int i, c; struct timeval tv; fd_set rd; strlcpy(nick, getenv("USER"), sizeof nick); for(i = 1; i < argc; i++) { c = argv[i][1]; if(argv[i][0] != '-' || argv[i][2]) c = -1; switch(c) { case 'h': if(++i < argc) host = argv[i]; break; case 'p': if(++i < argc) port = atoi(argv[i]); break; case 'n': if(++i < argc) strlcpy(nick, argv[i], sizeof nick); break; case 'k': if(++i < argc) password = argv[i]; break; case 'v': eprint("sic-"VERSION", ? 2005-2007 Anselm R. Garbe, Nico Golde\n"); default: eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n"); } } /* init */ i = dial(host, port); srv = fdopen(i, "r+"); /* login */ if(password) sout("PASS %s", password); sout("NICK %s", nick); sout("USER %s localhost %s :%s", nick, host, nick); fflush(srv); setbuf(stdout, nil); setbuf(srv, nil); for(;;) { /* main loop */ FD_ZERO(&rd); FD_SET(0, &rd); FD_SET(fileno(srv), &rd); tv.tv_sec = 120; tv.tv_usec = 0; i = select(fileno(srv) + 1, &rd, 0, 0, &tv); if(i < 0) { if(errno == EINTR) continue; eprint("sic: error on select():"); } else if(i == 0) { if(time(nil) - trespond >= PINGTIMEOUT) eprint("sic shutting down: parse timeout\n"); sout("PING %s", host); continue; } if(FD_ISSET(fileno(srv), &rd)) { if(fgets(bufin, sizeof bufin, srv) == nil) eprint("sic: remote host closed connection\n"); parsesrv(bufin); trespond = time(nil); } if(FD_ISSET(0, &rd)) { if(fgets(bufin, sizeof bufin, stdin) == nil) eprint("sic: broken pipe\n"); parsein(bufin); } } return 0; }
#include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> static void eprint(const char *fmt, ...) { va_buf(bufout, fmt); fprintf(stderr, "%s", bufout); if(fmt[0] && fmt[strlen(fmt)-1] == ':') fprintf(stderr, " %s\n", strerror(errno)); exit(1); } static int dial(char *host, int port) { struct hostent *hp; static struct sockaddr_in addr; int i; if((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) eprint("sic: cannot connect host '%s':", host); if(nil == (hp = gethostbyname(host))) eprint("sic: cannot resolve hostname '%s': %s\n", host, hstrerror(h_errno)); addr.sin_family = AF_INET; addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); if(connect(i, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) eprint("sic: cannot connect host '%s':", host); return i; } #define strlcpy _strlcpy static void strlcpy(char *to, const char *from, int l) { strncpy(to, from, l-1); to[l-1] = '\0'; } static void eat(char **s, int (*p)(int), int r) { char *q; for(q=*s; *q && p(*q) == r; q++) ; *s = q; } static char* tok(char **s) { char *p; eat(s, isspace, 1); p = *s; eat(s, isspace, 0); if(**s) *(*s)++ = '\0'; return p; } static char* ctok(char **s, int c) { char *p, *q; q = *s; for(p=q; *p && *p != c; p++) ; if(*p) *p++ = '\0'; *s = p; return q; }