#include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "ctype.h" #include "externs.h" #include "username.h" extern char **argvec; #define IDENTD_PORT 113 #if defined(USERNAMES) #if !defined(SYNC_USERNAMES) static #endif char *run_identd(const struct sockaddr *lcl, const struct sockaddr *rem, int sslen) { int s; int r; char buf[10240]; char *bp; int l; struct timeval end; struct timeval now; int ms; struct sockaddr_storage lss; struct sockaddr_storage rss; int slen; int lport; int rport; struct pollfd pfd; if (lcl->sa_family != rem->sa_family) { return(dup_string("(AFs differ)")); } switch (lcl->sa_family) { case AF_INET: if (sslen != sizeof(struct sockaddr_in)) return(dup_string("(AF_INET length wrong)")); lport = ntohs(((const struct sockaddr_in *)lcl)->sin_port); rport = ntohs(((const struct sockaddr_in *)rem)->sin_port); *((struct sockaddr_in *)&lss) = *(const struct sockaddr_in *)lcl; ((struct sockaddr_in *)&lss)->sin_port = 0; *((struct sockaddr_in *)&rss) = *(const struct sockaddr_in *)rem; ((struct sockaddr_in *)&rss)->sin_port = htons(IDENTD_PORT); slen = sizeof(struct sockaddr_in); break; case AF_INET6: if (sslen != sizeof(struct sockaddr_in6)) return(dup_string("(AF_INET6 length wrong)")); lport = ntohs(((const struct sockaddr_in6 *)lcl)->sin6_port); rport = ntohs(((const struct sockaddr_in6 *)rem)->sin6_port); *((struct sockaddr_in6 *)&lss) = *(const struct sockaddr_in6 *)lcl; ((struct sockaddr_in6 *)&lss)->sin6_port = 0; *((struct sockaddr_in6 *)&rss) = *(const struct sockaddr_in6 *)rem; ((struct sockaddr_in6 *)&rss)->sin6_port = htons(IDENTD_PORT); slen = sizeof(struct sockaddr_in6); break; default: return(dup_string("(unknown AF)")); break; } s = socket(lcl->sa_family,SOCK_STREAM,0); if (s < 0) { malprintf(&bp,"(socket: %s)",strerror(errno)); return(bp); } if (bind(s,(struct sockaddr *)&lss,slen) < 0) { malprintf(&bp,"(bind: %s)",strerror(errno)); close(s); return(bp); } if (connect(s,(struct sockaddr *)&rss,slen) < 0) { malprintf(&bp,"(connect: %s)",strerror(errno)); close(s); return(bp); } snprintf(&buf[0],sizeof(buf),"%hu,%hu\r\n",rport,lport); write(s,&buf[0],strlen(&buf[0])); shutdown(s,1); bp = &buf[0]; l = sizeof(buf) - 1; gettimeofday(&end,0); end.tv_sec += 60; while (l > 0) { pfd.fd = s; pfd.events = POLLIN | POLLRDNORM; gettimeofday(&now,0); if (now.tv_sec > end.tv_sec) { if (l < 16) bp -= 16; strcpy(bp,"(timeout)"); close(s); return(dup_string(&buf[0])); } ms = ((end.tv_sec - now.tv_sec) * 1000) + ((1000000 - now.tv_usec) / 1000); if (ms < 1) ms = 1; r = poll(&pfd,1,ms); if (r < 0) { if (errno == EINTR) continue; sprintf(&buf[0],"(poll: %s)",strerror(errno)); close(s); return(dup_string(&buf[0])); } if ((r > 0) && (pfd.revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP))) { r = read(s,bp,l); if (r < 0) { sprintf(&buf[0],"(read: %s)",strerror(errno)); close(s); return(dup_string(&buf[0])); } if (r == 0) break; bp += r; l -= r; } } close(s); r = bp - &buf[0]; if ((r > 0) && (bp[-1] == '\n')) { r --; bp --; } if ((r > 0) && (bp[-1] == '\r')) { r --; bp --; } l = bp - &buf[0]; *bp = '\0'; l = 0; for (bp=&buf[0];*bp;bp++) { if ( (*(unsigned char *)bp < 32) || ( (*(unsigned char *)bp >= 127) && (*(unsigned char *)bp < 160) ) ) { l --; } else if (l != 0) { bp[l] = *bp; } } if (l != 0) bp[l] = '\0'; l = (bp+l) - &buf[0]; bp = index(&buf[0],':'); if (! bp) { int i; fprintf(stderr,"no colon 1:"); for (i=0;i 32) { fprintf(stderr," ..."); break; } fprintf(stderr," %02x",((unsigned char *)&buf[0])[i]); } fprintf(stderr,"\n"); l = strlen(&buf[0]); if (l > 100) l = 100; bcopy(&buf[0],&buf[20],l); bcopy("(error: no colon 1: ",&buf[0],20); buf[l+20] = ')'; buf[l+21] = '\0'; return(dup_string(&buf[0])); } do bp++; while (*bp && Cisspace(*bp)); if (!bcmp(bp,"USERID",6)) { bp = index(bp+6,':'); if (! bp) return(dup_string("(error: no colon after USERID)")); bp = index(bp+1,':'); if (! bp) return(dup_string("(error: no colon after OS)")); return(bp+1); } else if (!bcmp(bp,"ERROR",5)) { return(dup_string(bp)); } return(dup_string("(error: neither USERID nor ERROR)")); } #endif #if defined(USERNAMES) && !defined(SYNC_USERNAMES) int username_fd; int username_px; void fork_username_process(void) { int p[2]; int pid; int npend; #define MAXPEND 1024 int pend[MAXPEND]; int npoll; struct pollfd pfds[MAXPEND+1]; int npfds; int i; int j; socketpair(AF_UNIX,SOCK_STREAM,0,&p[0]); pid = fork(); if (pid) { username_fd = p[0]; close(p[1]); return; } signal(SIGINT,SIG_IGN); username_fd = p[1]; close(p[0]); for (i=getdtablesize()-1;i>=0;i--) { if ((i != username_fd) && (i != 2)) close(i); } npend = 0; while (1) { while (1) { pid = wait3(0,WNOHANG,0); if (pid <= 0) break; } j = 0; for (i=0;i= 0) { if (j != i) pend[j] = pend[i]; pfds[j].fd = pend[j]; pfds[j].events = POLLIN | POLLRDNORM; j ++; } } npend = j; npoll = j; if (npend < MAXPEND) { pfds[j].fd = username_fd; pfds[j].events = POLLIN | POLLRDNORM; j ++; } npfds = j; i = poll(&pfds[0],npfds,INFTIM); if (i < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: poll: %s\n",argvec[0],strerror(errno)); exit(0); } if ((npoll < MAXPEND) && (pfds[npoll].revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP))) #define RQLEN (sizeof(int) + sizeof(struct sockaddr_storage [2])) { unsigned char rqbuf[RQLEN]; struct sockaddr_storage ss[2]; int sslen; if (Read(username_fd,&rqbuf[0],RQLEN) < 0) exit(0); bcopy(&rqbuf[0],&sslen,sizeof(int)); bcopy(&rqbuf[sizeof(int)],&ss[0],sizeof(struct sockaddr_storage [2])); socketpair(AF_UNIX,SOCK_STREAM,0,&p[0]); pend[npend++] = p[0]; pid = fork(); if (pid == 0) { char *s; int n; unsigned char len; struct iovec iov[4]; close(username_fd); for (i=npend-1;i>=0;i--) close(pend[i]); s = run_identd((void *)&ss[0],(void *)&ss[1],sslen); n = strlen(s); len = (n > 255) ? 255 : n; iov[0].iov_base = &sslen; iov[0].iov_len = sizeof(sslen); iov[1].iov_base = &ss[0]; iov[1].iov_len = sizeof(ss); iov[2].iov_base = &len; iov[2].iov_len = 1; iov[3].iov_base = s; iov[3].iov_len = len; writev(p[1],&iov[0],4); free(s); exit(0); } close(p[1]); } for (i=npoll-1;i>=0;i--) { if (pfds[i].revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP)) #define SAS (sizeof(int) + sizeof(struct sockaddr_storage [2])) { unsigned char buf[SAS+1+255]; if ( (Read(pend[i],&buf[0],SAS+1) == 0) && (Read(pend[i],&buf[SAS+1],buf[SAS]) == 0) ) { write(username_fd,&buf[0],SAS+1+buf[SAS]); } #undef SAS close(pend[i]); pend[i] = -1; } } } } #endif