static int smtp_server(CLI *c) { char line[STRLEN]; if(RFC2487(c, c->local_rfd.fd)==0) return 0; /* Return if RFC 2487 is not used */ if(fdscanf(c, c->remote_fd.fd, "220%[^\n]", line)!=1) { s_log(LOG_ERR, "Unknown server welcome"); return -1; } if(fdprintf(c, c->local_wfd.fd, "220%s + stunnel", line)<0) return -1; if(fdscanf(c, c->local_rfd.fd, "EHLO %[^\n]", line)!=1) { s_log(LOG_ERR, "Unknown client EHLO"); return -1; } if(fdprintf(c, c->local_wfd.fd, "250-%s Welcome", line)<0) return -1; if(fdprintf(c, c->local_wfd.fd, "250 STARTTLS")<0) return -1; if(fdscanf(c, c->local_rfd.fd, "STARTTLS", line)<0) { s_log(LOG_ERR, "STARTTLS expected"); return -1; } if(fdprintf(c, c->local_wfd.fd, "220 Go ahead")<0) return -1; return 0; }
static int smtp_client(CLI *c) { char line[STRLEN]; do { /* Copy multiline greeting */ if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; if(fdprintf(c, c->local_wfd.fd, "%s", line)<0) return -1; } while(strncasecmp(line,"220-",4)==0); if(fdprintf(c, c->remote_fd.fd, "EHLO localhost")<0) /* Send an EHLO command */ return -1; do { /* Skip multiline reply */ if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; } while(strncasecmp(line,"250-",4)==0); if(strncasecmp(line,"250 ",4)!=0) { /* Error */ s_log(LOG_ERR, "Remote server is not RFC 1425 compliant"); return -1; } if(fdprintf(c, c->remote_fd.fd, "STARTTLS")<0) /* Send STARTTLS command */ return -1; do { /* Skip multiline reply */ if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; } while(strncasecmp(line,"220-",4)==0); if(strncasecmp(line,"220 ",4)!=0) { /* Error */ s_log(LOG_ERR, "Remote server is not RFC 2487 compliant"); return -1; } return 0; }
static int auth_user(CLI *c) { struct servent *s_ent; /* structure for getservbyname */ SOCKADDR_UNION ident; /* IDENT socket name */ int fd; /* IDENT socket descriptor */ char name[STRLEN]; int retval; int error; if(!c->opt->username) return 0; /* -u option not specified */ if((fd=socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM, 0))<0) { sockerror("socket (auth_user)"); return -1; } if(alloc_fd(fd)) return -1; memcpy(&ident, &c->peer_addr.addr[0], sizeof(SOCKADDR_UNION)); s_ent=getservbyname("auth", "tcp"); if(s_ent) { ident.in.sin_port=s_ent->s_port; } else { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } if(connect(fd, &ident.sa, addr_len(ident))) { error=get_last_socket_error(); if(error!=EINPROGRESS && error!=EWOULDBLOCK) { sockerror("ident connect (auth_user)"); closesocket(fd); return -1; } if(connect_wait(c, fd, c->opt->timeout_connect)) { /* error */ closesocket(fd); return -1; } } s_log(LOG_DEBUG, "IDENT server connected"); if(fdprintf(c, fd, "%u , %u", ntohs(c->peer_addr.addr[0].in.sin_port), ntohs(c->opt->local_addr.addr[0].in.sin_port))<0) { sockerror("fdprintf (auth_user)"); closesocket(fd); return -1; } if(fdscanf(c, fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) { s_log(LOG_ERR, "Incorrect data from IDENT server"); closesocket(fd); return -1; } closesocket(fd); retval=strcmp(name, c->opt->username) ? -1 : 0; safestring(name); s_log(LOG_INFO, "IDENT resolved remote user to %s", name); return retval; }
static int nntp_client(CLI *c) { char line[STRLEN]; if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; if(strncasecmp(line,"200 ",4) && strncasecmp(line,"201 ",4)) { s_log(LOG_ERR, "Unknown server welcome"); return -1; } if(fdprintf(c, c->local_wfd.fd, "%s", line)<0) return -1; if(fdprintf(c, c->remote_fd.fd, "STARTTLS")<0) return -1; if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; if(strncasecmp(line,"382 ",4)) { s_log(LOG_ERR, "Server does not support TLS"); return -1; } return 0; }
static int pop3_server(CLI *c) { char line[STRLEN]; if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0) return -1; if(fdprintf(c, c->local_wfd.fd, "%s + stunnel", line)<0) return -1; if(fdscanf(c, c->local_rfd.fd, "%[^\n]", line)<0) return -1; if(!strncasecmp(line, "CAPA", 4)) { /* Client wants RFC 2449 extensions */ if(fdprintf(c, c->local_wfd.fd, "-ERR Stunnel does not support capabilities")<0) return -1; if(fdscanf(c, c->local_rfd.fd, "%[^\n]", line)<0) return -1; } if(strncasecmp(line, "STLS", 4)) { s_log(LOG_ERR, "Client does not want TLS"); return -1; } if(fdprintf(c, c->local_wfd.fd, "+OK Stunnel starts TLS negotiation")<0) return -1; return 0; }
static int auth_user(CLI *c) { struct servent *s_ent; /* structure for getservbyname */ struct sockaddr_in ident; /* IDENT socket name */ int fd; /* IDENT socket descriptor */ char name[STRLEN]; int retval; if(!c->opt->username) return 0; /* -u option not specified */ if((fd=socket(AF_INET, SOCK_STREAM, 0))<0) { sockerror("socket (auth_user)"); return -1; } alloc_fd(fd); memcpy(&ident, &c->addr, sizeof(ident)); s_ent=getservbyname("auth", "tcp"); if(!s_ent) { log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.sin_port=htons(113); } else { ident.sin_port=s_ent->s_port; } if(connect(fd, (struct sockaddr *)&ident, sizeof(ident))<0) { switch(get_last_socket_error()) { case EINPROGRESS: /* retry */ log(LOG_DEBUG, "connect #1 (auth_user): EINPROGRESS: retrying"); break; case EWOULDBLOCK: /* retry */ log(LOG_DEBUG, "connect #1 (auth_user): EWOULDBLOCK: retrying"); break; default: sockerror("connect #1 (auth_user)"); closesocket(fd); return -1; } if(waitforsocket(fd, 1 /* write */, c->opt->timeout_busy)<1) { closesocket(fd); return -1; } if(connect(fd, (struct sockaddr *)&ident, sizeof(ident))<0) { switch(get_last_socket_error()) { case EINVAL: /* WIN32 is strange... */ log(LOG_DEBUG, "connect #2 (auth_user): EINVAL: ok"); case EISCONN: /* ok */ break; /* success */ default: sockerror("connect #2 (auth_user))"); closesocket(fd); return -1; } } } log(LOG_DEBUG, "IDENT server connected"); if(fdprintf(c, fd, "%u , %u", ntohs(c->addr.sin_port), ntohs(c->opt->localport))<0) { sockerror("fdprintf (auth_user)"); closesocket(fd); return -1; } if(fdscanf(c, fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) { log(LOG_ERR, "Incorrect data from IDENT server"); closesocket(fd); return -1; } closesocket(fd); retval=strcmp(name, c->opt->username) ? -1 : 0; safestring(name); log(LOG_INFO, "IDENT resolved remote user to %s", name); return retval; }