📄 passchange.c
字号:
/* * RADIUS Remote Authentication Dial In User Service * * * Livingston Enterprises, Inc. 6920 Koll Center Parkway Pleasanton, CA 94566 * * Copyright 1992 Livingston Enterprises, Inc. * * Permission to use, copy, modify, and distribute this software for any * purpose and without fee is hereby granted, provided that this copyright * and permission notice appear on all copies and supporting documentation, * the name of Livingston Enterprises, Inc. not be used in advertising or * publicity pertaining to distribution of the program without specific * prior permission, and notice be given in supporting documentation that * copying and distribution is by permission of Livingston Enterprises, Inc. * * Livingston Enterprises, Inc. makes no representations about the suitability * of this software for any purpose. It is provided "as is" without express * or implied warranty. * *//* * Copyright [C] The Regents of the University of Michigan and Merit Network, * Inc. 1992, 1993, 1994, 1995, 1996, 1997, 1998 All Rights Reserved * * Permission to use, copy, and modify this software and its documentation * for any purpose and without fee is hereby granted, provided: * * 1) that the above copyright notice and this permission notice appear in all * copies of the software and derivative works or modified versions thereof, * * 2) that both the copyright notice and this permission and disclaimer notice * appear in all supporting documentation, and * * 3) that all derivative works made from this material are returned to the * Regents of the University of Michigan and Merit Network, Inc. with * permission to copy, to display, to distribute, and to make derivative * works from the provided material in whole or in part for any purpose. * * Users of this code are requested to notify Merit Network, Inc. of such use * by sending email to aaa-admin@merit.edu * * Please also use aaa-admin@merit.edu to inform Merit Network, Inc of any * derivative works. * * Distribution of this software or derivative works or the associated * documentation is not allowed without an additional license. * * Licenses for other uses are available on an individually negotiated * basis. Contact aaa-license@merit.edu for more information. * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF THE * UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INC. DO NOT WARRANT THAT THE * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. The Regents of the * University of Michigan and Merit Network, Inc. shall not be liable for any * special, indirect, incidental or consequential damages with respect to any * claim by Licensee or any third party arising from use of the software. * * Merit AAA Server Support * Merit Network, Inc. * 4251 Plymouth Road, Suite C. * Ann Arbor, Michigan, USA 48105-2785 * * attn: John Vollbrecht * voice: 734-764-9430 * fax: 734-647-3185 * email: aaa-admin@merit.edu * *//* * * Public entry points in this file: * * pw_expired * */static char rcsid[] = "$Id: passchange.c,v 1.1.1.1 2001/08/10 20:49:28 bonze Exp $";#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/file.h>#include <net/if.h>#include <netinet/in.h>#include <stdio.h>#include <netdb.h>#include <errno.h>#include <memory.h>#include <signal.h>#include <syslog.h>#include "radius.h"extern UINT4 expiration_seconds;extern UINT4 warning_seconds;extern int debug_flag;extern int allow_pw_changing;static int set_expiration PROTO((VALUE_PAIR *, VALUE_PAIR *, UINT4));static int rad_passchange PROTO((AUTH_REQ *, int, char *));static AATV passwd_aatv = DEF_AATV_DIRECT("PASSWD", rad_passchange);AATVPTR rad_passwd_aatv = & passwd_aatv;/************************************************************************* * * Function: rad_passchange * * Purpose: Change a users password * *************************************************************************/static intrad_passchange (authreq, value, afpar)AUTH_REQ *authreq;int value;char *afpar;{ int result; VALUE_PAIR *namepair; VALUE_PAIR *newpasspair; VALUE_PAIR *oldpasspair; VALUE_PAIR *curpass; VALUE_PAIR *user_check; VALUE_PAIR *user_deny; VALUE_PAIR *user_reply; char pw_digest[AUTH_VECTOR_LEN]; char string[64]; char passbuf[AUTH_PASS_LEN]; int i; int secretlen; static char *func = "rad_passchange"; dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); /* * The allow_pw_changing global variable is defined in the * engine and set by a command line option. */ if (allow_pw_changing == 0) { return EV_NAK; } /* Get the username */ namepair = get_vp (authreq->cur_request, PW_USER_NAME); if (namepair == (VALUE_PAIR *) NULL) { logit (LOG_DAEMON, LOG_ERR, "%s: from %s - No User name supplied", func, ip_hostname (authreq->ipaddr)); return EV_NAK; } /* * Look the user up in the database */ if (user_find (NULL, namepair->strvalue, 0, &user_check, &user_deny, &user_reply, 0) != 0) { logit (LOG_DAEMON, LOG_ERR, "%s: from %s - Invalid User: %s", func, ip_hostname (authreq->ipaddr), namepair->strvalue); return EV_NAK; } /* * Validate the user - * * We have to unwrap this in a special way to decrypt the old and new * passwords. The MD5 calculation is based on the old password. The * vector is different. The old password is encrypted using the * encrypted new password as its vector. The new password is * encrypted using the random encryption vector in the request * header. */ /* Extract the attr-value pairs for the old and new passwords */ newpasspair = get_vp (authreq->cur_request, PW_USER_PASSWORD); oldpasspair = get_vp (authreq->cur_request, PW_OLD_PASSWORD); /* Verify that both encrypted passwords were supplied */ if (newpasspair == (VALUE_PAIR *) NULL || oldpasspair == (VALUE_PAIR *) NULL) { /* Missing one of the passwords */ logit (LOG_DAEMON, LOG_ERR, "%s: from %s - Missing Password: %s", func, ip_hostname (authreq->ipaddr), namepair->strvalue); list_free (user_check); list_free (user_deny); list_free (user_reply); return EV_NAK; } /* Get the current password from the database */ curpass = get_vp_ci (user_check, CI_USER_PASSWORD, 0); if ((curpass == (VALUE_PAIR *) NULL) || (curpass->strvalue == (char *) NULL)) { /* Missing our local copy of the password */ logit (LOG_DAEMON, LOG_ERR, "%s: from %s - Missing Local Password: %s", func, ip_hostname (authreq->ipaddr), namepair->strvalue); list_free (user_check); list_free (user_deny); list_free (user_reply); return EV_NAK; } if (strcmp (curpass->strvalue, "UNIX") == 0) /* Old Livinstong traces */ { /* Can't change passwords that aren't in users file */ logit (LOG_DAEMON, LOG_ERR, "%s: from %s: system password change not allowed: %s\n", func, ip_hostname (authreq->ipaddr), namepair->strvalue); list_free (user_check); list_free (user_deny); list_free (user_reply); return EV_NAK; } /* Decrypt the old password */ secretlen = strlen (curpass->strvalue); memcpy (string, curpass->strvalue, secretlen); memcpy (string + secretlen, newpasspair->strvalue, AUTH_VECTOR_LEN); md5_calc (pw_digest, string, AUTH_VECTOR_LEN + secretlen); memcpy ((char *) passbuf, oldpasspair->strvalue, AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN; i++) { passbuf[i] ^= pw_digest[i]; } /* Did they supply the correct password ??? */ if (strncmp (passbuf, curpass->strvalue, AUTH_PASS_LEN) != 0) { logit (LOG_DAEMON, LOG_ERR, "%s: from %s - Incorrect Password: %s", func, ip_hostname (authreq->ipaddr), namepair->strvalue); list_free (user_check); list_free (user_deny); list_free (user_reply); return EV_NAK; } /* Decrypt the new password */ memcpy (string, curpass->strvalue, secretlen); memcpy (string + secretlen, (char *) authreq->repvec, AUTH_VECTOR_LEN); md5_calc (pw_digest, string, AUTH_VECTOR_LEN + secretlen); memcpy ((char *) passbuf, newpasspair->strvalue, AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN; i++) { passbuf[i] ^= pw_digest[i]; }#ifdef ASCEND /* Update the users password in the memory cache. */ if (change_pw (namepair->strvalue, 0, curpass, passbuf) != 0) { logit (LOG_DAEMON, LOG_ERR, "%s: from %s - Cannot change cached password: %s", func, ip_hostname (authreq->ipaddr), namepair->strvalue); list_free (user_check); list_free (user_deny); list_free (user_reply); return EV_NAK; } /* * Also change it in the check list so it gets * reflected in the file update. */#endif /* ASCEND */ /* Update the users password. */ avpair_string_mod (curpass, passbuf, -1); /* Add a new expiration date if we are aging passwords */ if (expiration_seconds != (UINT4) 0) { set_expiration (user_check, user_reply, expiration_seconds); }#ifdef ASCEND /* Update the cached expiration time */ update_expire (namepair->strvalue, 0, user_check);#endif /* ASCEND */ /* Update the database */ if (user_update (namepair->strvalue, user_check, user_deny, user_reply) != 0) { result = EV_NAK; } else { result = EV_ACK; } list_free (user_check); list_free (user_deny); list_free (user_reply); return result;} /* end of rad_passchange () *//************************************************************************* * * Function: set_expiration * * Purpose: Set the new expiration time by updating or adding * the Expiration attribute-value pair. * *************************************************************************/static intset_expiration (user_check, user_reply, expiration)VALUE_PAIR *user_check;VALUE_PAIR *user_reply;UINT4 expiration;{ VALUE_PAIR *exppair; VALUE_PAIR *prev; VALUE_PAIR *vp; UINT4 zero = 0; struct timeval tp; struct timezone tzp; static char *func = "set_expiration"; dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); if (user_check == (VALUE_PAIR *) NULL) { return (-1); } /* Look for an existing expiration entry */ exppair = user_check; prev = (VALUE_PAIR *) NULL; while (exppair != (VALUE_PAIR *) NULL) { if (exppair->attribute == CI_EXPIRATION) { break; } prev = exppair; exppair = exppair->next; } if (exppair == (VALUE_PAIR *) NULL) { exppair = avpair_add (&prev->next, CI_EXPIRATION, &zero, 0); } /* calculate a new expiration */ vp = NULL_VP;#ifdef ASCEND for (vp = user_reply; vp != NULL_VP; vp = vp->next) { if (vp->attribute == CI_ASCEND_PW_LIFETIME && vp->ap->vendor_id == VC_ASCEND) { break; } }#endif /* ASCEND */ gettimeofday (&tp, &tzp); if (vp == NULL_VP) { exppair->lvalue = tp.tv_sec + expiration; } else { exppair->lvalue = tp.tv_sec + vp->lvalue * SECONDS_PER_DAY; } return (0);} /* end of set_expiration () *//************************************************************************* * * Function: pw_expired * * Purpose: Tests to see if the user's password has expired. * * Return: Number of days before expiration if a warning is required * otherwise zero for success and -1 for failure. * *************************************************************************/intpw_expired (exptime, check_items)UINT4 exptime;VALUE_PAIR *check_items;{ int exp_remain_int; UINT4 exp_remain; UINT4 warn_secs; VALUE_PAIR *item; struct timeval tp; struct timezone tzp; warn_secs = warning_seconds;#ifdef ASCEND /* Items in the users file take precedence over configuration values */ for (item = check_items; item != NULL_VP; item = item->next) { if (item->attribute == CI_ASCEND_PW_WARNING && item->ap->vendor_id == VC_ASCEND) { warn_secs = item->lvalue * SECONDS_PER_DAY; } }#endif /* ASCEND */ if (expiration_seconds == (UINT4) 0) { return -1; } gettimeofday (&tp, &tzp); if (tp.tv_sec > exptime) { return -1; } if (warn_secs != (UINT4) 0) { if (tp.tv_sec > exptime - warning_seconds) { exp_remain = exptime - tp.tv_sec; exp_remain /= (UINT4) SECONDS_PER_DAY; exp_remain_int = exp_remain + 1; return (exp_remain_int); } } return 0;} /* end of pw_expired () */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -