/* * Copyright (c) 2002-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* * OpenFWTK project authmgr client protocol functions * * (C) Copyright 2002 ArkanoiD */ /* * This module implements legacy protocol supported by TIS authsrv * shipped with Gauntlet and FWTK. * * Some important security notes: * * 1) It is _strongly_ recommended not to use it without encryption. * With encryption turned off any proxy can mimick authsrv communications * using access to loopback interface. It is _extremely_ dangerous if * you run ssl proxy that supports CONNECT method. * * 2) Even worse, encryption is not designed properly and uses weak DES * algorithm. So the whole protocol is flawed. Standard authsrv banner * repeats on every session and may be used for brute force attack. * * 3) Gauntlet and exportable fwtk version do not support even that. */ #include #include #include #include #include #include #include #include #include #include "firewall.h" #include "firewall2.h" #include "fwfunc.h" #include "auth.h" #ifdef OpenBSD #include #else #include #endif static int authfd = -1; static des_key_schedule deskey; static int auth_encrypt = 0; static void tohex(raw,hex,len) char *raw; char *hex; int len; { char *hdig="0123456789ABCDEF"; while(len > 0){ len--; *hex++ = hdig[((*raw)>>4)&0xf]; *hex++ = hdig[(*raw++)&0xf]; } *hex++ = '\0'; return; } static void fromhex(hex,raw,len) char *hex; char *raw; int len; { int x; char *s; s = raw; for (x = 0; x < len; x+=2) { *(s++) = ((isdigit(hex[x]) ? hex[x] - '0' : hex[x] - 'A' + 10) << 4) + (isdigit(hex[x+1]) ? hex[x+1] - '0' : hex[x+1] - 'A' + 10); } *s = '\0'; } int auth_open(cfp) Cfg *cfp; { Cfg *cf; char *authserver = AUTH_DEFAULTSERVER; int authport = AUTH_DEFAULTPORT; des_cblock cblock; if (authfd != -1) return(0); if ((cf = cfg_get("authserver",cfp))) { if (cf->argc < 1) { syslog(LLEV,"fwtkcfgerr: authserver not provided, line %d",cf->ln); return(1); } authserver = cf->argv[0]; /* Check whether UNIX socket is specified */ if(!strncasecmp(authserver, "unix:", strlen("unix:"))) { authport = UNIX_SOCK; } /* Don't try read a port number if UNIX socket has been specified */ if (authport != UNIX_SOCK && cf->argc >= 2) authport = str_to_port(cf->argv[1]); if (!auth_encrypt && cf->argc >= 3) { auth_encrypt = 1; des_string_to_key(cf->argv[2],&cblock); bzero(cf->argv[2],strlen(cf->argv[2])); des_set_key(&cblock,deskey); } } if (!authserver) { syslog(LLEV,"fwtkcfgerr: no authserver defined! cannot authenticate!"); return(1); } if (authport <= 0 && strncasecmp(authserver, "unix:", strlen("unix:"))) { syslog(LLEV,"fwtkcfgerr: no authport defined! cannot authenticate!"); return(1); } else if(!strncasecmp(authserver, "unix:", strlen("unix:"))) { if (((authfd = conn_server_unixsock(authserver,NULL)) < 0)) { syslog(LLEV,"fwtksyserr: cannot connect to authentication server via unix socket %s, %s", authserver, strerror(errno)); return(-1); } } else { if (((authfd = conn_server(authserver,authport,0,NULL)) < 0)) { syslog(LLEV,"fwtksyserr: cannot connect to authentication server, %s", strerror(errno)); return(-1); } } signal(SIGPIPE,SIG_IGN); return(0); } int auth_close() { if (authfd >= 0) { close(authfd); authfd = -1; return(0); } return(0); } int auth_send(buf) char *buf; { int len; int old_linestyle; char xbuf[MAX_STR * 2]; char cbuf[MAX_STR * 2]; char ebuf[MAX_STR * 2]; char *p; if (authfd < 0) { syslog(LLEV,"fwtksyserr: no connection to authentication server"); return(1); } if (!buf || !*buf) return(1); bzero(xbuf,sizeof(xbuf)); strlcpy(xbuf,buf,sizeof(xbuf)); for (p = xbuf; *p; p++) { if ((*p == '\n') || (*p == '\r')) { syslog(LLEV,"securityalert: possible command injection attack in authsrv stream"); syslog(LLEV,"fwtksyserr: proxy logic error - unsafe data in auth_send()"); return(1); } if ((!isprint(*p) && (*p != '\t')) || !isascii(*p)) { syslog(LLEV,"securityalert: non-printable character %x in authsrv interaction", *p); *p = '\?'; } } if (auth_encrypt) { des_cblock iv; bzero(iv,sizeof(iv)); /* Sic! */ if ((len = strlen(buf) + 1) % 8) len += 8 + (len % 8); if ( len > (sizeof(cbuf) / 2)) { syslog(LLEV,"fwtksyserr: buffer overrun in auth_send()"); return(1); } #ifdef OpenBSD des_cbc_encrypt((des_cblock*) xbuf, (des_cblock*) cbuf,len, deskey,&iv,DES_ENCRYPT); #else des_cbc_encrypt((const unsigned char*) xbuf, (unsigned char*) cbuf,len, deskey,&iv,DES_ENCRYPT); #endif tohex(cbuf,ebuf,len); p = ebuf; } else p = xbuf; old_linestyle = proxy_linestyle; sosetline(SO_LLF); if (sosay(authfd,p)) { syslog(LLEV,"fwtksyserr: error writing to authentication server"); sosetline(old_linestyle); return(1); } else { sosetline(old_linestyle); return(0); } } int auth_recv(buf,size) char *buf; int size; { int old_linestyle; int len; char xbuf[MAX_STR * 2]; char ebuf[MAX_STR * 2]; if (authfd < 0) { syslog(LLEV,"fwtksyserr: no connection to authentication server"); return(1); } old_linestyle = proxy_linestyle; sosetline(SO_LLF); if (((len = sogets(authfd,xbuf,sizeof(xbuf))) <= 1)) { syslog(LLEV,"fwtksyserr: auth_recv: read error %s", strerror(errno)); sosetline(old_linestyle); return(1); } sosetline(old_linestyle); if (xbuf[len-1] == '\n') xbuf[len-1] = '\0'; else { syslog(LLEV,"fwtksyserr: unterminated line from authsrv"); return(1); } if (auth_encrypt) { des_cblock iv; fromhex(xbuf,ebuf,len); bzero(iv,sizeof(iv)); /* Sic! */ #ifdef OpenBSD des_cbc_encrypt((des_cblock*) ebuf,(des_cblock*) xbuf,len, deskey,&iv,DES_DECRYPT); #else des_cbc_encrypt((const unsigned char*) ebuf, (unsigned char*) xbuf,len, deskey,&iv,DES_DECRYPT); #endif } if (strlen(xbuf) >= size) { syslog(LLEV,"fwtksyserr: auth_recv: buffer overflow"); return(1); } strlcpy(buf,xbuf,size); return(0); } char* sanitize_parm(parm) char *parm; { static char buf[MAX_STR * 2]; char *pi,*po; int needquotes = 0; char *hdig="0123456789ABCDEF"; *(po = buf) = '\''; po++; /* * Here we do some ugly escaping for unwanted characters */ for(pi = parm; *pi; pi++) { if (po > buf + sizeof(buf) - 5) { syslog(LLEV,"fwtksyserr: buffer overrun in parameter processing"); break; } needquotes |= ((*pi == '\t') || (*pi == '\"') || (*pi == ' ')); if (!isascii(*pi) || (*pi == '\'')) { *(po++) = '%'; *(po++) = hdig[((*pi)>>4)&0xf]; *(po++) = hdig[(*pi)&0xf]; continue; } if (!isprint(*pi)) { if (*pi == '\r' || *pi == '\n') syslog(LLEV,"securityalert: possible command injection attack in authsrv stream"); syslog(LLEV,"fwtksyserr: proxy logic error - unsafe auth_perm value"); *(po++) = '?'; continue; } *(po++) = *pi; } if (needquotes) { *(po++) = '\''; *(po++) = '\0'; return(buf); } else { *(po++) = '\0'; return(buf + 1); } } int auth_perm(cfp,name,oper,dest,op) Cfg *cfp; char *name; char *oper; char *dest; char **op; { char buf[MAX_STR]; if (authfd < 0) { if (auth_open(cfp)) return(1); if(auth_recv(buf,sizeof(buf))) { auth_close(); return(-1); } if(strncmp(buf,"Authsrv ready",13)) { syslog(LLEV,"fwtksyserr: bad response from authentication server"); auth_close(); return(1); } } bzero(buf,sizeof(buf)); /* Be compatible */ if (*proxy_stats.riaddr) snprintf(buf,sizeof(buf),"operation user %.24s %.100s %.128s %.512s",name,oper,proxy_stats.riaddr,dest); else snprintf(buf,sizeof(buf),"operation user %.24s %.100s 'unknown' %.512s",name,oper,dest); if (op) { char **opp; for (opp = op; *opp; opp++) { if ((strlen(buf) + strlen(*opp) + 1) >= sizeof(buf)) { syslog(LLEV,"fwtksyserr: auth_perm operation string buffer overflow"); auth_close(); return(-1); } strlcat(buf," ",sizeof(buf)); strlcat(buf,sanitize_parm(*opp),sizeof(buf)); } } if(auth_send(buf)) { auth_close(); return(-1); } if(auth_recv(buf,sizeof(buf))) { auth_close(); return(-1); } auth_close(); if(!strncmp(buf,"ok",2)) return(0); if(!strncmp(buf,"Perm",4)) return(1); return(-1); }