/* (C) 1997 Mike Shoyher msh@corbina.net, msh@apache.lexa.ru */ #include #include #include #include #include #include #include #include #include #include #include #include"tac_plus.h" #include "tacplus_client.h" int tac_sequence; int tac_session_id; int tac_maxtry=3; int tac_timeout=15; int tac_fd; char tac_key[128]; struct sockaddr_in tac_port; struct hostent *tac_h; struct servent *tac_serv; char ourhost[128]; int ourhost_len; char* ourtty="Virtual00"; int ourtty_len; char* tac_err="NONE"; void fill_tac_hdr(struct tac_plus_pak_hdr* hdr) { hdr->version=TAC_PLUS_VER_0; hdr->type=TAC_PLUS_AUTHEN; hdr->seq_no=tac_sequence; hdr->encryption=TAC_PLUS_CLEAR; hdr->session_id=tac_session_id; } int send_data(void* buf, int buf_len, int fd); int read_reply(void** data); /* Need to specify the lengths, becuase CHAP passwords etc may have NULs in them */ void send_auth_cont(char* msg, int msg_len); int make_auth(char* username, int user_len, char* password, int password_len, int authen_type) { struct tac_plus_pak_hdr hdr; struct authen_start as; int datalength; void* buf; void* data; int data_len; int buf_len; struct authen_reply* ar; fill_tac_hdr(&hdr); datalength=TAC_AUTHEN_START_FIXED_FIELDS_SIZE; as.action= TAC_PLUS_AUTHEN_LOGIN ; as.priv_lvl= TAC_PLUS_PRIV_LVL_MIN ; as.authen_type = authen_type ; as.service= TAC_PLUS_AUTHEN_SVC_LOGIN ; as.user_len=as.port_len=as.rem_addr_len=as.data_len=0; if (authen_type != TAC_PLUS_AUTHEN_TYPE_ASCII) { /* This will be a version 1 request with the username and password in the start */ hdr.version=TAC_PLUS_VER_1; as.user_len = user_len; as.data_len = password_len; } buf=malloc(buf_len=TAC_PLUS_HDR_SIZE+TAC_AUTHEN_START_FIXED_FIELDS_SIZE+ourtty_len+ourhost_len+as.user_len+as.data_len); /* Append user name if required */ bcopy(username,buf+datalength+TAC_PLUS_HDR_SIZE,as.user_len); datalength+=(as.user_len); bcopy(ourtty,buf+datalength+TAC_PLUS_HDR_SIZE,ourtty_len); datalength+=(ourtty_len); as.port_len=ourtty_len; bcopy(ourhost,buf+datalength+TAC_PLUS_HDR_SIZE,ourhost_len); datalength+=(ourhost_len); as.rem_addr_len=ourhost_len; /* Append password if required */ bcopy(password,buf+datalength+TAC_PLUS_HDR_SIZE,as.data_len); datalength+=(as.data_len); hdr.datalength= htonl(datalength) ; bcopy(&hdr,buf,TAC_PLUS_HDR_SIZE); bcopy(&as,buf+TAC_PLUS_HDR_SIZE,TAC_AUTHEN_START_FIXED_FIELDS_SIZE); md5_xor(buf, buf+TAC_PLUS_HDR_SIZE, tac_key); send_data(buf,buf_len,tac_fd); free(buf); while ((data_len=read_reply(&data))!=-1){ ar=data; switch (ar->status) { case TAC_PLUS_AUTHEN_STATUS_GETUSER: free(data); send_auth_cont(username, user_len); break; case TAC_PLUS_AUTHEN_STATUS_GETPASS: free(data); send_auth_cont(password, password_len); break; case TAC_PLUS_AUTHEN_STATUS_PASS: return 1; case TAC_PLUS_AUTHEN_STATUS_FAIL: tac_err="Authentification failed"; return 0; default : tac_err="Protocol error"; return 0; } } tac_err="Unknown error"; return 0; } void send_auth_cont(char* msg, int msg_len) { struct tac_plus_pak_hdr hdr; struct authen_cont ac; int datalength; void* buf; int buf_len; buf_len=TAC_PLUS_HDR_SIZE+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE+msg_len; buf=malloc(buf_len); fill_tac_hdr(&hdr); ac.user_data_len=ac.flags=0; ac.user_msg_len=htons(msg_len); bcopy(msg,buf+TAC_PLUS_HDR_SIZE+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE,msg_len); datalength=msg_len+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE; hdr.datalength=htonl(datalength); bcopy(&hdr,buf,TAC_PLUS_HDR_SIZE); bcopy(&ac,buf+TAC_PLUS_HDR_SIZE,TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE); md5_xor(buf, buf+TAC_PLUS_HDR_SIZE, tac_key); send_data(buf,buf_len,tac_fd); free(buf); } void myerror (char* s) { printf("%s\n",s); exit(1); } int init_tac_session(char* host_name, char* port_name, char* key, int timeout) { gethostname(ourhost,127); ourhost_len=strlen(ourhost); ourtty_len=strlen(ourtty); srand(time(NULL)); if (timeout>0) tac_timeout=timeout; strcpy(tac_key,key); tac_session_id=rand(); tac_sequence=1; tac_port.sin_family = AF_INET; if (*host_name>='0' && *host_name<='9') { tac_port.sin_addr.s_addr = inet_addr(host_name); } else { tac_h = gethostbyname(host_name); if (!tac_h) { /*myerror("Cannot resolve host name");*/ tac_err="Cannot resolve host name"; return -1; } tac_port.sin_addr = *((struct in_addr *) tac_h->h_addr); } if (port_name==NULL) port_name="tacacs"; if (*port_name>='0' && *port_name<='9') { tac_port.sin_port=htons (atoi(port_name)); } else { tac_serv=getservbyname(port_name,"tcp"); if (tac_serv) tac_port.sin_port=tac_serv->s_port; else { /*myerror("Unknown port");*/ tac_err="Unknown port"; return -1; } } if((tac_fd = socket (AF_INET, SOCK_STREAM, 0))<0) return -1; if (connect (tac_fd, (struct sockaddr *) &tac_port, sizeof tac_port) < 0) return -1; return tac_fd; } int send_data(void* buf, int buf_len, int fd) { fd_set fds; int rr; int try; struct timeval tv; FD_ZERO(&fds); FD_SET(fd,&fds); tv.tv_sec = tac_timeout; tv.tv_usec = 0; for(try=0;try