📄 auth_md5.c
字号:
/* * Program: CRAM-MD5 authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 21 October 1998 * Last Edited: 13 April 2000 * * Copyright 2000 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * above copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made available * "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *//* MD5 context */#define MD5BLKLEN 64 /* MD5 block length */#define MD5DIGLEN 16 /* MD5 digest length */typedef struct { unsigned long chigh; /* high 32bits of byte count */ unsigned long clow; /* low 32bits of byte count */ unsigned long state[4]; /* state (ABCD) */ unsigned char buf[MD5BLKLEN]; /* input buffer */ unsigned char *ptr; /* buffer position */} MD5CONTEXT;/* Prototypes */long auth_md5_valid (void);long auth_md5_client (authchallenge_t challenger,authrespond_t responder, NETMBX *mb,void *stream,unsigned long *trial,char *user);char *auth_md5_server (authresponse_t responder,int argc,char *argv[]);char *auth_md5_pwd (char *user);char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl);void md5_init (MD5CONTEXT *ctx);void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len);void md5_final (unsigned char *digest,MD5CONTEXT *ctx);static void md5_transform (unsigned long *state,unsigned char *block);static void md5_encode (unsigned char *dst,unsigned long *src,int len);static void md5_decode (unsigned long *dst,unsigned char *src,int len);/* Authenticator linkage */AUTHENTICATOR auth_md5 = { AU_SECURE, /* secure authenticator */ "CRAM-MD5", /* authenticator name */ auth_md5_valid, /* check if valid */ auth_md5_client, /* client method */ auth_md5_server, /* server method */ NIL /* next authenticator */};/* Check if CRAM-MD5 valid on this system * Returns: T, always */long auth_md5_valid (void){ struct stat sbuf; /* server forbids MD5 if no MD5 enable file */ if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL; return T; /* MD5 is otherwise valid */}/* Client authenticator * Accepts: challenger function * responder function * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */long auth_md5_client (authchallenge_t challenger,authrespond_t responder, NETMBX *mb,void *stream,unsigned long *trial,char *user){ char pwd[MAILTMPLEN],resp[MAILTMPLEN]; void *chal; unsigned long cl; /* get challenge */ if (chal = (*challenger) (stream,&cl)) { /* prompt user */ mm_login (mb,user,pwd,*trial); if (pwd[0]) { /* got password, build response */ sprintf (resp,"%s %s",user,hmac_md5 (chal,cl,pwd,strlen (pwd))); fs_give ((void **) &chal);/* don't need challenge any moe */ /* send credentials, allow retry if OK */ if ((*responder) (stream,resp,strlen (resp)) && !(chal = (*challenger) (stream,&cl))) return (long) ++*trial; } /* user requested abort */ else (*responder) (stream,NIL,0); } /* flush any challenge left behind */ if (chal) fs_give ((void **) &chal); *trial = 0; /* retries not permitted */ return NIL; /* return failure */}/* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL * * This is much hairier than it needs to be due to the necessary of zapping * the password data. */char *auth_md5_server (authresponse_t responder,int argc,char *argv[]){ char *ret = NIL; char *p,*u,*user,*authuser,*hash,chal[MAILTMPLEN]; unsigned long cl,pl; /* generate challenge */ sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (), (unsigned long) time (0),mylocalhost ()); /* send challenge, get user and hash */ if (user = (*responder) (chal,cl = strlen (chal),NIL)) { /* got user, locate hash */ if (hash = strrchr (user,' ')) { *hash++ = '\0'; /* tie off user */ /* see if authentication user */ if (authuser = strchr (user,'*')) *authuser++ = '\0'; if (authuser && *authuser) { if (!(p = auth_md5_pwd (authuser))) p = auth_md5_pwd (lcase (authuser)); } else if (!(p = auth_md5_pwd (user))) p = auth_md5_pwd (lcase (user)); if (p) { /* quickly verify password */ u = strcmp (hash,hmac_md5 (chal,cl,p,pl = strlen (p))) ? NIL : user; memset (p,0,pl); /* erase sensitive information */ fs_give ((void **) &p); /* flush erased password */ /* now log in for real */ if (u && authserver_login (u,authuser,argc,argv)) ret = myusername (); } } fs_give ((void **) &user); } if (!ret) sleep (3); /* slow down possible cracker */ return ret;}/* Return MD5 password for user * Accepts: user name * Returns: plaintext password if success, else NIL * * This is much hairier than it needs to be due to the necessary of zapping * the password data. */char *auth_md5_pwd (char *user){ struct stat sbuf; int fd = open (MD5ENABLE,O_RDONLY,NIL); char *s,*t,*buf; char *ret = NIL; if (fd >= 0) { /* found the file? */ if (!fstat (fd,&sbuf)) { /* yes, slurp it into memory */ read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); for (s = strtok (buf,"\015\012"); s; s = ret ? NIL : strtok (NIL,"\015\012")) /* must be valid entry line */ if ((*s != '#') && (t = strchr (s,'\t'))) { *t++ = '\0'; /* found tab, tie off user, point to pwd */ if (*s && *t && !strcmp (s,user)) ret = cpystr (t); } /* erase sensitive information from buffer */ memset (buf,0,sbuf.st_size + 1); fs_give ((void **) &buf); /* flush the buffer */ } close (fd); /* don't need file any longer */ } return ret; /* return password */}/* APOP server login * Accepts: challenge * desired user name * purported MD5 * argument count * argument vector * Returns: authenticated user name or NIL */char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]){ int i,j; char *ret = NIL; char *s,*authuser,tmp[MAILTMPLEN]; unsigned char digest[MD5DIGLEN]; MD5CONTEXT ctx; char *hex = "0123456789abcdef"; /* see if authentication user */ if (authuser = strchr (user,'*')) *authuser++ = '\0'; if (authuser && *authuser) { if (!(s = auth_md5_pwd (authuser))) s = auth_md5_pwd (lcase (authuser)); } else if (!(s = auth_md5_pwd (user))) s = auth_md5_pwd (lcase (user)); if (s) { /* only if found password */ md5_init (&ctx); /* initialize MD5 context */ /* build string to get MD5 digest */ sprintf (tmp,"%.128s%.128s",chal,s); memset (s,0,strlen (s)); /* erase sensitive information */ fs_give ((void **) &s); /* flush erased password */ md5_update (&ctx,(unsigned char *) tmp,strlen (tmp)); memset (tmp,0,MAILTMPLEN); /* erase sensitive information */ md5_final (digest,&ctx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -