#include #include #include #include #include #include #include #include #include #define TA_A_BAD_PASSWD 4 #define TA_A_NO_SUCH_USER 5 #define TA_A_NOT_AUTH_FOR_SLIP 6 #define TA_A_UNKNOWN 10 extern int client_debug; static struct sockaddr_in s_sock[64],c_sock[64]; static CREDENTIALS cred[64]; static char tktfl[512]={0}; static KTEXT_ST ktxt[64]; int maxl=0; static int do_encrypt=0; static int sock=0-1; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [ This function establishes an unauthenticated connection to service [ THESERVICE. A socket is returned if it succeeds, otherwise a -1 or -2 [ and a string is stored in respbuf indicating the type of failure. -1 [ indicates that there was a fatal non-recoverable error; -2 indicates [ that a timeout of some sort occured, and that retrying may be helpful. */ estab_unauth_client_conn(theservice,respbuf,remhost) char *theservice; char *respbuf; char *remhost; { int i; struct servent *serv; struct hostent *host; struct in_addr locaddr; char *tp,tbuf[2]; char hostname[128]; int sock; respbuf[0]=0; /* Look up service */ if ((serv = getservbyname(theservice, "tcp")) == NULL) { sprintf(respbuf, "service unknown: %s/tcp\n", theservice); return(-1); } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { sprintf(respbuf,"socket():%s\n",strerror(errno)); return(-1); } host=gethostbyname(remhost); /* Set server's address */ bzero((char *)&(s_sock[sock]), sizeof(s_sock[sock])); bcopy(host->h_addr, (char *)&(s_sock[sock].sin_addr), host->h_length); if(client_debug) printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock[sock].sin_addr)); s_sock[sock].sin_family = AF_INET; s_sock[sock].sin_port = serv->s_port; if (gethostname(hostname, sizeof(hostname)) < 0) { perror("gethostname"); close(sock); unlink_tkt_fl(); return(-1); } if ((host = gethostbyname(hostname)) == (struct hostent *)0) { sprintf(respbuf, "%s: unknown host\n", hostname); close(sock); unlink_tkt_fl(); return(-1); } bzero((char *)&(c_sock[sock]), sizeof(c_sock[sock])); bcopy(host->h_addr, (char *)&(c_sock[sock].sin_addr), sizeof(locaddr)); c_sock[sock].sin_family = AF_INET; /* Bind it to set the address; kernel will fill in port # */ if (bind(sock, (struct sockaddr *)&(c_sock[sock]), sizeof((c_sock[sock]))) < 0) { close(sock); sprintf(respbuf,"bind():%s\n",strerror(errno)); return(-1); } if(connect(sock,&(s_sock[sock]),sizeof(s_sock[sock]))<0) { close(sock); sprintf(respbuf,"connect():%s\n",strerror(errno)); return(-2); } bzero((char *) &(c_sock[sock]), sizeof(c_sock[sock])); i = sizeof(c_sock[sock]); if (getsockname(sock, (struct sockaddr *)&(c_sock[sock]), &i) < 0) { sprintf(respbuf,"getsockname():%s\n",strerror(errno)); close(sock); return(-2); } return(sock); } /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [ This routine sends a Kerberos-authenticated message COMM of length [ MLEN to the server connected to SOCK. A response is returned in respbuf, [ which must be an array of at least 512 characters. If an error occurs, [ it returns either -2 or -1. -2 indicates that the message wasn't [ sent. -1 indicates that the message was potentially received by the [ server but either no acknowledgement or improper acknowledgement was [ received. (The distinction is important, since successful transmission [ of a request may indicate that the server executed the request; if the [ message wasn't sent to the server, it could be retried). */ send_mesg(sock,comm,mlen,respbuf,timeout) int sock; char *comm; int mlen; char *respbuf; struct timeval *timeout; { int i,len; char tbuf[1024],*dptr; MSG_DAT msg_data; fd_set ptrs; C_Block key; if(do_encrypt) { des_key_schedule sched; int x; if(srvtab_to_key("authen","styx","magnus","/etc/srvtab",&key)) { fprintf(stderr,"srvtab_to_key failed\n"); } des_key_sched(key,sched); des_pcbc_encrypt(comm,tbuf,mlen,sched,key,ENCRYPT); dptr=tbuf; len=mlen+8; /* des_pcbc_encrypt always rounds to a multiple of 8 bytes; this will ensure that we send the entire encrypted string */ } else dptr=comm; i = write(sock, dptr, (int) len); if (i != len) { sprintf(respbuf,"Error sending request:%s\n",strerror(errno)); finish_up_kerberos(sock); return(-2); } /* Get a response */ FD_ZERO(&ptrs); FD_SET(sock,&ptrs); if(timeout!=NULL) i=select(sock+1,&ptrs,NULL,NULL,timeout); if((timeout==NULL) || (i>0)) i = read(sock, tbuf, 1024); if(i<=0) { sprintf(respbuf,"Error receiving message back:%s\n",strerror(errno)); finish_up_kerberos(sock); return(-1); } strcpy(respbuf,tbuf); if(client_debug) sprintf("%s\n",tbuf); return(sock); } finish_up_kerberos(sock) int sock; { shutdown(sock,2); close(sock); unlink_tkt_fl(); } /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [ Send a message COMM of length MLEN to service THESERVICE over [ previously-established SOCK (sock is -1 if no previous connection exists). [ A response is returned in RESPBUF, which must be an array of at least [ 512 characters. NODISC indicates that a unique ticket file for this [ instance should be created. The value returned is either a file descriptor [ or -1 on failure. (The file descriptor must be saved for further [ invocations). The function tries to send the message a maximum of 5 [ times, if a recoverable error is reported. */ retry_com_get_resp(sock,theservice,remhost,comm,mlen,respbuf,nodisc,timeout,canrepeatflag) int sock; char *theservice; char *remhost; char *comm; int mlen; char *respbuf; int nodisc; struct timeval *timeout; int canrepeatflag; { int x; again: if(sock<0) { for(x=0;(x<5) && ((sock=estab_unauth_client_conn(theservice,respbuf,remhost))<-1);x++) sleep(2); if(sock<0) return(sock); } sock=send_mesg(sock,comm,mlen,respbuf,timeout); if((sock<-1) || ((sock<0) && canrepeatflag)) goto again; close(sock); return(sock); } unlink_tkt_fl() { if(tktfl[0]) { unlink(tktfl); tktfl[0]=0; } } /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - [ Turn client encryption on */ client_do_encrypt() { do_encrypt=1; } /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [ Authenticate "username" with "password" for a "service" [ from a "host". [ [ Send and encrypted request with "username", "password" and "service" [ to the "host" and wait for the sesponse. Retries upto five times [ if there is no response. [ [ returns 0 if authentication passes. [ returns -1 if authentication fails. */ authenticate_user(username,password,service,host) char *username,*password,*service,*host; { char buf[512],resp[512],*p; int firsttime=1; client_do_encrypt(); /* Require encryption between server and client */ strcpy(buf,username); p=buf; while(*p) p++; *(p++)='\001'; strcpy(p,password); while(*p) p++; *(p++)='\001'; strcpy(p,service); sock=retry_com_get_resp(sock,"authen",host,buf,strlen(buf)+1,resp,1,NULL,1); if(sock<0 || resp[0]!=0) { /* printf("%s\n",resp); */ if( strcmp(resp,"Password incorrect.")==0) return( TA_A_BAD_PASSWD); if( strcmp(resp,"No such user.")==0) return(TA_A_NO_SUCH_USER); if( strcmp(resp,"Not authorized for service.")==0) return(TA_A_NOT_AUTH_FOR_SLIP); return(TA_A_UNKNOWN); } return(0); }