char *fd_getline(CLI *c, int fd) { char *line, *tmpline; int ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { s_poll_init(c->fds); s_poll_add(c->fds, fd, 1, 0); /* read */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("fd_getline: s_poll_wait"); str_free(line); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "fd_getline: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); str_free(line); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "fd_getline: s_poll_wait: Unknown result"); str_free(line); longjmp(c->err, 1); /* error */ } if(allocated<ptr+1) { allocated*=2; line=str_realloc(line, allocated); } switch(readsocket(fd, line+ptr, 1)) { case -1: /* error */ sockerror("fd_getline: readsocket"); str_free(line); longjmp(c->err, 1); case 0: /* EOF */ s_log(LOG_ERR, "fd_getline: Unexpected socket close"); str_free(line); longjmp(c->err, 1); } if(line[ptr]=='\r') continue; if(line[ptr]=='\n') break; if(line[ptr]=='\0') break; if(++ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "fd_getline: Line too long"); str_free(line); longjmp(c->err, 1); } } line[ptr]='\0'; tmpline=str_dup(line); safestring(tmpline); s_log(LOG_DEBUG, " <- %s", tmpline); str_free(tmpline); return line; }
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; }
void fd_putline(CLI *c, int fd, const char *line) { char *tmpline; const char crlf[]="\r\n"; int len; tmpline=str_printf("%s%s", line, crlf); len=strlen(tmpline); s_write(c, fd, tmpline, len); tmpline[len-2]='\0'; /* remove CRLF */ safestring(tmpline); s_log(LOG_DEBUG, " -> %s", tmpline); str_free(tmpline); }
void fdputline(CLI *c, int fd, char *line) { char tmpline[STRLEN]; const char crlf[]="\r\n"; int len; if(strlen(line)+2>=STRLEN) { /* 2 for crlf */ s_log(LOG_ERR, "Line too long in fdputline"); longjmp(c->err, 1); } safecopy(tmpline, line); safeconcat(tmpline, crlf); len=strlen(tmpline); write_blocking(c, fd, tmpline, len); tmpline[len-2]='\0'; /* remove CRLF */ safestring(tmpline); s_log(LOG_DEBUG, " -> %s", tmpline); }
void fdgetline(CLI *c, int fd, char *line) { char logline[STRLEN]; s_poll_set fds; int ptr; for(ptr=0;;) { s_poll_zero(&fds); s_poll_add(&fds, fd, 1, 0); /* read */ switch(s_poll_wait(&fds, c->opt->timeout_busy)) { case -1: sockerror("fdgetline: s_poll_wait"); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "fdgetline: s_poll_wait timeout"); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "fdgetline: s_poll_wait unknown result"); longjmp(c->err, 1); /* error */ } switch(readsocket(fd, line+ptr, 1)) { case -1: /* error */ sockerror("readsocket (fdgetline)"); longjmp(c->err, 1); case 0: /* EOF */ s_log(LOG_ERR, "Unexpected socket close (fdgetline)"); longjmp(c->err, 1); } if(line[ptr]=='\r') continue; if(line[ptr]=='\n') break; if(!line[ptr]) break; if(++ptr==STRLEN) { s_log(LOG_ERR, "Input line too long"); longjmp(c->err, 1); } } line[ptr]='\0'; safecopy(logline, line); safestring(logline); s_log(LOG_DEBUG, " <- %s", logline); }
static int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) { /* our verify callback function */ SSL *ssl; CLI *c; char subject_name[STRLEN]; /* retrieve application specific data */ ssl=X509_STORE_CTX_get_ex_data(callback_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); c=SSL_get_ex_data(ssl, cli_index); /* certificate name for logging */ X509_NAME_oneline(X509_get_subject_name(callback_ctx->current_cert), subject_name, STRLEN); safestring(subject_name); s_log(LOG_DEBUG, "Starting certificate verification: depth=%d, %s", callback_ctx->error_depth, subject_name); if(!cert_check(c, callback_ctx, preverify_ok)) { s_log(LOG_WARNING, "Certificate check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } if(!crl_check(c, callback_ctx)) { s_log(LOG_WARNING, "CRL check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } if(c->opt->option.ocsp && !ocsp_check(c, callback_ctx)) { s_log(LOG_WARNING, "OCSP check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } /* errnum=X509_STORE_CTX_get_error(ctx); */ s_log(LOG_NOTICE, "Certificate accepted: depth=%d, %s", callback_ctx->error_depth, subject_name); return 1; /* accept connection */ }
static int connect_local(CLI *c) { /* spawn local process */ #if defined (USE_WIN32) || defined (__vms) s_log(LOG_ERR, "LOCAL MODE NOT SUPPORTED ON WIN32 and OpenVMS PLATFORM"); return -1; #else /* USE_WIN32, __vms */ char env[3][STRLEN], name[STRLEN], *portname; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if (c->opt->option.pty) { char tty[STRLEN]; if(pty_allocate(fd, fd+1, tty, STRLEN)) { return -1; } s_log(LOG_DEBUG, "%s allocated", tty); } else { if(make_sockets(fd)) return -1; } pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); return -1; case 0: /* child */ closesocket(fd[0]); dup2(fd[1], 0); dup2(fd[1], 1); if(!options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); safecopy(env[0], "REMOTE_HOST="); safeconcat(env[0], c->accepting_address); portname=strrchr(env[0], ':'); if(portname) /* strip the port name */ *portname='\0'; putenv(env[0]); if(c->opt->option.transparent) { putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); /* For Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { safecopy(env[1], "SSL_CLIENT_DN="); X509_NAME_oneline(X509_get_subject_name(peer), name, STRLEN); safestring(name); safeconcat(env[1], name); putenv(env[1]); safecopy(env[2], "SSL_CLIENT_I_DN="); X509_NAME_oneline(X509_get_issuer_name(peer), name, STRLEN); safestring(name); safeconcat(env[2], name); putenv(env[2]); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execv failed */ _exit(1); default: break; } /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); #ifdef FD_CLOEXEC fcntl(fd[0], F_SETFD, FD_CLOEXEC); #endif return fd[0]; #endif /* USE_WIN32,__vms */ }
std::string getExecutablePath() { #if ARX_PLATFORM == ARX_PLATFORM_MACOSX uint32_t bufsize = 0; // Obtain required size _NSGetExecutablePath(NULL, &bufsize); std::vector<char> exepath(bufsize); if(_NSGetExecutablePath(&exepath.front(), &bufsize) == 0) { char exerealpath[MAXPATHLEN]; if(realpath(&exepath.front(), exerealpath)) { return exerealpath; } } ARX_UNUSED(executablePath); #elif defined(ARX_HAVE_WINAPI) std::vector<char> buffer; buffer.resize(MAX_PATH); if(GetModuleFileNameA(NULL, buffer.data(), buffer.size()) > 0) { return std::string(buffer.data(), buffer.size()); } #else // Try to get the path from OS-specific procfs entries #ifdef ARX_HAVE_READLINK std::vector<char> buffer(1024); // Linux if(try_readlink(buffer, "/proc/self/exe")) { return std::string(buffer.begin(), buffer.end()); } // BSD if(try_readlink(buffer, "/proc/curproc/file")) { return std::string(buffer.begin(), buffer.end()); } // Solaris if(try_readlink(buffer, "/proc/self/path/a.out")) { return std::string(buffer.begin(), buffer.end()); } #endif // FreeBSD #if defined(ARX_HAVE_SYSCTL) && defined(CTL_KERN) && defined(KERN_PROC) \ && defined(KERN_PROC_PATHNAME) && ARX_PLATFORM == ARX_PLATFORM_BSD \ && defined(PATH_MAX) int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; char pathname[PATH_MAX]; size_t size = sizeof(pathname); int error = sysctl(mib, 4, pathname, &size, NULL, 0); if(error != -1 && size > 0 && size < sizeof(pathname)) { return safestring(pathname, size); } #endif // Solaris #ifdef ARX_HAVE_GETEXECNAME const char * execname = getexecname(); if(execname != NULL) { return execname; } #endif // Fall back to argv[0] if possible if(executablePath != NULL) { std::string path(executablePath); if(path.find('/') != std::string::npos) { return path; } } #endif // Give up - we couldn't determine the exe path. return std::string(); }
static int connect_local(CLI *c) { /* spawn local process */ char *name, *portname; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else make_sockets(c, fd); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ closesocket(fd[0]); set_nonblock(fd[1], 0); /* switch back to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ name=str_dup(c->accepted_address); portname=strrchr(name, ':'); if(portname) /* strip the port name */ *portname='\0'; putenv(str_printf("REMOTE_HOST=%s", name)); if(c->opt->option.transparent_src) { putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); /* for Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { name=X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_DN=%s", name)); name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execv failed */ _exit(1); default: /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); return fd[0]; } }
static void auth_user(CLI *c) { #ifndef _WIN32_WCE struct servent *s_ent; /* structure for getservbyname */ #endif SOCKADDR_UNION ident; /* IDENT socket name */ char *line, *type, *system, *user; if(!c->opt->username) return; /* -u option not specified */ c->fd=s_socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM, 0, 1, "socket (auth_user)"); if(c->fd<0) longjmp(c->err, 1); memcpy(&ident, &c->peer_addr.addr[0], sizeof ident); #ifndef _WIN32_WCE s_ent=getservbyname("auth", "tcp"); if(s_ent) { ident.in.sin_port=s_ent->s_port; } else #endif { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } if(connect_blocking(c, &ident, addr_len(ident))) longjmp(c->err, 1); s_log(LOG_DEBUG, "IDENT server connected"); fdprintf(c, c->fd, "%u , %u", ntohs(c->peer_addr.addr[0].in.sin_port), ntohs(c->opt->local_addr.addr[0].in.sin_port)); line=fdgetline(c, c->fd); closesocket(c->fd); c->fd=-1; /* avoid double close on cleanup */ type=strchr(line, ':'); if(!type) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *type++='\0'; system=strchr(type, ':'); if(!system) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *system++='\0'; if(strcmp(type, " USERID ")) { s_log(LOG_ERR, "Incorrect INETD response type"); str_free(line); longjmp(c->err, 1); } user=strchr(system, ':'); if(!user) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *user++='\0'; while(*user==' ') /* skip leading spaces */ ++user; if(strcmp(user, c->opt->username)) { safestring(user); s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)", c->accepted_address, user); str_free(line); longjmp(c->err, 1); } s_log(LOG_INFO, "IDENT authentication passed"); str_free(line); }
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; }
NOEXPORT int connect_local(CLI *c) { /* spawn local process */ char *name, host[40]; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else if(make_sockets(fd)) longjmp(c->err, 1); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ closesocket(fd[0]); set_nonblock(fd[1], 0); /* switch back to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ if(!getnameinfo(&c->peer_addr.sa, c->peer_addr_len, host, 40, NULL, 0, NI_NUMERICHOST)) { /* just don't set these variables if getnameinfo() fails */ putenv(str_printf("REMOTE_HOST=%s", host)); if(c->opt->option.transparent_src) { #ifndef LIBDIR #define LIBDIR "." #endif #ifdef MACH64 putenv("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); putenv("LD_PRELOAD_64=" LIBDIR "/" MACH64 "/libstunnel.so"); #elif __osf /* for Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); #else putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); #endif } } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { name=X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_DN=%s", name)); name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execvp failed */ _exit(1); default: /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); return fd[0]; } }
void s_log(int level, const char *format, ...) { va_list ap; char *text, *stamp, *id; struct LIST *tmp; #ifdef USE_WIN32 DWORD libc_error; #else int libc_error; #endif int socket_error; time_t gmt; struct tm *timeptr; #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) struct tm timestruct; #endif TLS_DATA *tls_data; tls_data=tls_get(); if(!tls_data) { tls_data=tls_alloc(NULL, NULL, "log"); s_log(LOG_ERR, "INTERNAL ERROR: Uninitialized TLS at %s, line %d", __FILE__, __LINE__); } /* performance optimization: skip the trivial case early */ if(log_mode==LOG_MODE_CONFIGURED && level>tls_data->opt->log_level) return; libc_error=get_last_error(); socket_error=get_last_socket_error(); /* format the id to be logged */ time(&gmt); #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) timeptr=localtime_r(&gmt, ×truct); #else timeptr=localtime(&gmt); #endif stamp=str_printf("%04d.%02d.%02d %02d:%02d:%02d", timeptr->tm_year+1900, timeptr->tm_mon+1, timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); id=str_printf("LOG%d[%s]", level, tls_data->id); /* format the text to be logged */ va_start(ap, format); text=str_vprintf(format, ap); va_end(ap); safestring(text); CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_LOG_MODE]); if(log_mode==LOG_MODE_BUFFER) { /* save the text to log it later */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LOG_BUFFER]); tmp=str_alloc_detached(sizeof(struct LIST)); tmp->next=NULL; tmp->opt=tls_data->opt; tmp->level=level; tmp->stamp=stamp; str_detach(tmp->stamp); tmp->id=id; str_detach(tmp->id); tmp->text=text; str_detach(tmp->text); if(tail) tail->next=tmp; else head=tmp; tail=tmp; CRYPTO_THREAD_write_unlock(stunnel_locks[LOCK_LOG_BUFFER]); } else { /* ready log the text directly */ log_raw(tls_data->opt, level, stamp, id, text); str_free(stamp); str_free(id); str_free(text); } CRYPTO_THREAD_read_unlock(stunnel_locks[LOCK_LOG_MODE]); set_last_error(libc_error); set_last_socket_error(socket_error); }
static void auth_user(CLI * c, char *accepted_address) { struct servent *s_ent; SOCKADDR_UNION ident; char *line, *type, *system, *user; if (!c->opt->username) return; if (c->peer_addr.sa.sa_family == AF_UNIX) { s_log(LOG_INFO, "IDENT not supported on Unix sockets"); return; } c->fd = s_socket(c->peer_addr.sa.sa_family, SOCK_STREAM, 0, 1, "socket (auth_user)"); if (c->fd < 0) longjmp(c->err, 1); memcpy(&ident, &c->peer_addr, c->peer_addr_len); 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_blocking(c, &ident, addr_len(&ident))) longjmp(c->err, 1); s_log(LOG_DEBUG, "IDENT server connected"); fd_printf(c, c->fd, "%u , %u", ntohs(c->peer_addr.in.sin_port), ntohs(c->opt->local_addr.in.sin_port)); line = fd_getline(c, c->fd); closesocket(c->fd); c->fd = -1; type = strchr(line, ':'); if (!type) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *type++ = '\0'; system = strchr(type, ':'); if (!system) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *system++ = '\0'; if (strcmp(type, " USERID ")) { s_log(LOG_ERR, "Incorrect INETD response type"); str_free(line); longjmp(c->err, 1); } user = strchr(system, ':'); if (!user) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *user++ = '\0'; while (*user == ' ') ++user; if (strcmp(user, c->opt->username)) { safestring(user); s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)", accepted_address, user); str_free(line); longjmp(c->err, 1); } s_log(LOG_INFO, "IDENT authentication passed"); str_free(line); }