📄 auth_md5.c
字号:
/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== *//* * 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: 30 January 2007 *//* 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, char *service,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 * SASL service name * 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, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user){ char pwd[MAILTMPLEN]; void *challenge; unsigned long clen; long ret = NIL; /* get challenge */ if (challenge = (*challenger) (stream,&clen)) { pwd[0] = NIL; /* prompt user */ mm_login (mb,user,pwd,*trial); if (!pwd[0]) { /* user requested abort */ fs_give ((void **) &challenge); (*responder) (stream,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } else { /* got password, build response */ sprintf (pwd,"%.65s %.33s",user,hmac_md5 (challenge,clen, pwd,strlen (pwd))); fs_give ((void **) &challenge); /* send credentials, allow retry if OK */ if ((*responder) (stream,pwd,strlen (pwd))) { if (challenge = (*challenger) (stream,&clen)) fs_give ((void **) &challenge); else { ++*trial; /* can try again if necessary */ ret = LONGT; /* check the authentication */ } } } } memset (pwd,0,MAILTMPLEN); /* erase password in case not overwritten */ if (!ret) *trial = 65535; /* don't retry if bad protocol */ return ret;}/* 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. */static int md5try = MAXLOGINTRIALS;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'; /* get password */ if (p = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) { pl = strlen (p); u = (md5try && !strcmp (hash,hmac_md5 (chal,cl,p,pl))) ? user : NIL; 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 (); else if (md5try) --md5try; } } 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. That's why we don't use stdio here. */char *auth_md5_pwd (char *user){ struct stat sbuf; int fd = open (MD5ENABLE,O_RDONLY,NIL); unsigned char *s,*t,*buf,*lusr,*lret; char *r; char *ret = NIL; if (fd >= 0) { /* found the file? */ fstat (fd,&sbuf); /* yes, slurp it into memory */ read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); /* see if any uppercase characters in user */ for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++); /* yes, make lowercase copy */ lusr = *s ? lcase (cpystr (user)) : NIL; for (s = strtok_r ((char *) buf,"\015\012",&r),lret = NIL; s; s = ret ? NIL : strtok_r (NIL,"\015\012",&r)) /* must be valid entry line */ if (*s && (*s != '#') && (t = strchr (s,'\t')) && t[1]) { *t++ = '\0'; /* found tab, tie off user, point to pwd */ if (!strcmp (s,user)) ret = cpystr (t); else if (lusr && !lret) if (!strcmp (s,lusr)) lret = t; } /* accept case-independent name */ if (!ret && lret) ret = cpystr (lret); /* don't need lowercase copy any more */ if (lusr) fs_give ((void **) &lusr); /* 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'; /* get password */ if (s = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) { 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 + -