FreeBSD Bugzilla – Attachment 7093 Details for
Bug 15619
[patch] standard pppd(8) doesn't authenticate users with global-1 radiusd
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
file.diff
file.diff (text/plain), 398.70 KB, created by
Andrew Klyachkin
on 1999-12-22 07:00:02 UTC
(
hide
)
Description:
file.diff
Filename:
MIME Type:
Creator:
Andrew Klyachkin
Created:
1999-12-22 07:00:02 UTC
Size:
398.70 KB
patch
obsolete
>diff -rPu pppd.old/Makefile pppd/Makefile >--- pppd.old/Makefile Sun Aug 29 19:46:53 1999 >+++ pppd/Makefile Thu Dec 9 11:17:07 1999 >@@ -36,4 +36,8 @@ > DPADD+= ${LIBDES} > .endif > >+# RADIUS support >+CFLAGS+=-DRADIUS >+SRCS+=rad_dict.c rad_funcs.c rad_md5.c rad_regexp.c rad_sendserver.c rad_users.c rad_util.c pppradius.c >+ > .include <bsd.prog.mk> >diff -rPu pppd.old/auth.c pppd/auth.c >--- pppd.old/auth.c Sun Aug 29 19:46:54 1999 >+++ pppd/auth.c Sat Dec 11 13:50:48 1999 >@@ -80,6 +80,10 @@ > #endif > #include "pathnames.h" > >+#ifdef RADIUS >+#include "radius.h" >+#endif >+ > /* Used for storing a sequence of words. Usually malloced. */ > struct wordlist { > struct wordlist *next; >@@ -179,6 +183,8 @@ > minutes = (etime-stime)/60; > syslog(LOG_NOTICE, "Connection terminated, connected for %d minutes\n", > minutes > 1 ? minutes : 1); >+ if (reqradius) >+ rad_acct_stop(RADIUS_name); > } > > /* >@@ -247,11 +253,14 @@ > > phase = PHASE_AUTHENTICATE; > auth = 0; >+ syslog(LOG_DAEMON, "Authentication phase began"); > if (go->neg_chap) { > ChapAuthPeer(unit, our_name, go->chap_mdtype); > auth |= CHAP_PEER; > } else if (go->neg_upap) { >+ syslog(LOG_DAEMON, "Authentication with PAP"); > upap_authpeer(unit); >+ syslog(LOG_DAEMON, "Authntication finished"); > auth |= PAP_PEER; > } > if (ho->neg_chap) { >@@ -263,13 +272,18 @@ > if (!get_pap_passwd(passwd)) > syslog(LOG_ERR, "No secret found for PAP login"); > } >- upap_authwithpeer(unit, user, passwd); > auth |= PAP_WITHPEER; > } > auth_pending[unit] = auth; > >- if (!auth) >+ syslog(LOG_DAEMON, "Link established"); >+ >+ if (!auth) { >+ syslog(LOG_DAEMON, "óÏÂÉÒÁÅÍÓÑ × network phase"); > network_phase(unit); >+ } else { >+ syslog(LOG_DAEMON, "Stop network growth!"); >+ } > } > > /* >@@ -291,6 +305,7 @@ > did_authup = 1; > } > >+ syslog(LOG_DAEMON, "after path_authup"); > #ifdef CBCP_SUPPORT > /* > * If we negotiated callback, do it now. >@@ -670,7 +685,6 @@ > if (f == NULL) { > syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename); > ret = UPAP_AUTHNAK; >- > } else { > check_access(f, filename); > remote = ipwo->accept_remote? 0: ipwo->hisaddr; >@@ -691,6 +705,14 @@ > } > } > >+ /* here will be radius login */ >+#ifdef RADIUS >+ if (ret == UPAP_AUTHNAK && reqradius) >+ if (rad_auth(user, passwd) == OK_RC) >+ if (rad_acct_start(user) == OK_RC) >+ ret = UPAP_AUTHACK; >+#endif >+ > if (ret == UPAP_AUTHNAK) { > if (*msg == (char *) 0) > *msg = "Login incorrect"; >@@ -1028,7 +1050,16 @@ > } > > #else >- char *tty; >+ char *tty; >+ syslog(LOG_DAEMON, "plogout"); >+ >+#ifdef RADIUS >+ if (reqradius) { >+ if (rad_acct_stop(user) != OK_RC) { >+ syslog(LOG_DAEMON, "Can't stop accounting user"); >+ } >+ } >+#endif > > tty = devnam; > if (strncmp(tty, "/dev/", 5) == 0) >diff -rPu pppd.old/conf.h pppd/conf.h >--- pppd.old/conf.h Thu Jan 1 03:00:00 1970 >+++ pppd/conf.h Wed Aug 21 20:45:46 1996 >@@ -0,0 +1,97 @@ >+#ifndef CONF_H >+#define CONF_H >+ >+/* >+ * >+ * 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. >+ * >+ */ >+ >+/* >+ * @(#)conf.h 0.1 10/11/94 >+ */ >+ >+#define RADIUS_VERSION " 2.4.23C " /* MUST be surrounded by spaces */ >+ >+#if defined(__alpha) >+typedef unsigned int UINT4; >+typedef int INT4; >+#else /* defined(alpha) */ >+typedef unsigned long UINT4; >+typedef long INT4; >+#endif /* defined(alpha) */ >+ >+#if defined(unixware) || defined(sys5) || defined(M_UNIX) || defined(sun) >+#include <string.h> >+#else /* unixware */ >+#include <strings.h> >+#endif /* unixware */ >+ >+#if defined(bsdi) >+#include <machine/inline.h> >+#include <machine/endian.h> >+#else /* bsdi */ >+#ifndef __FreeBSD__ >+#include <malloc.h> >+#endif /* __FreeBSD__ */ >+#endif /* bsdi */ >+ >+/* #ifdef SYSV this is needed even on SunOS 4.1.3 */ >+#include <pwd.h> >+/* #endif XXX SYSV */ >+ >+#if defined(aix) >+#include <sys/select.h> >+#endif /* aix */ >+ >+#if defined(__hpux) >+#include <unistd.h> >+#endif /* __hpux */ >+ >+#ifdef USE_NDBM >+#include <ndbm.h> >+#include <fcntl.h> >+#endif /* USE_NDBM */ >+ >+#if defined(USE_DBM) >+#include <dbm.h> >+#if defined(sun) >+#define NULL 0 >+#endif /* sun */ >+#if defined(__sgi) >+#ifdef dbm_error64 >+#define store store64 >+#define dbminit dbminit64 >+#define dbmclose dbmclose64 >+#endif /* dbm_error64 */ >+#endif /* __sgi */ >+#endif /* USE_DBM */ >+ >+#if defined(linux) >+#include <unistd.h> >+#define MIN(a, b) ((a) < (b) ? (a) : (b)) >+#define MAX(a, b) ((a) > (b) ? (a) : (b)) >+#endif /* linux */ >+ >+#endif /* CONF_H */ >diff -rPu pppd.old/md4.c pppd/md4.c >--- pppd.old/md4.c Thu Jan 1 03:00:00 1970 >+++ pppd/md4.c Tue Dec 16 05:08:47 1997 >@@ -0,0 +1,298 @@ >+/* >+** ******************************************************************** >+** md4.c -- Implementation of MD4 Message Digest Algorithm ** >+** Updated: 2/16/90 by Ronald L. Rivest ** >+** (C) 1990 RSA Data Security, Inc. ** >+** ******************************************************************** >+*/ >+ >+/* >+** To use MD4: >+** -- Include md4.h in your program >+** -- Declare an MDstruct MD to hold the state of the digest >+** computation. >+** -- Initialize MD using MDbegin(&MD) >+** -- For each full block (64 bytes) X you wish to process, call >+** MD4Update(&MD,X,512) >+** (512 is the number of bits in a full block.) >+** -- For the last block (less than 64 bytes) you wish to process, >+** MD4Update(&MD,X,n) >+** where n is the number of bits in the partial block. A partial >+** block terminates the computation, so every MD computation >+** should terminate by processing a partial block, even if it >+** has n = 0. >+** -- The message digest is available in MD.buffer[0] ... >+** MD.buffer[3]. (Least-significant byte of each word >+** should be output first.) >+** -- You can print out the digest using MDprint(&MD) >+*/ >+ >+/* Implementation notes: >+** This implementation assumes that ints are 32-bit quantities. >+*/ >+ >+#define TRUE 1 >+#define FALSE 0 >+ >+/* Compile-time includes >+*/ >+#include <stdio.h> >+#include "md4.h" >+#include "pppd.h" >+ >+/* Compile-time declarations of MD4 "magic constants". >+*/ >+#define I0 0x67452301 /* Initial values for MD buffer */ >+#define I1 0xefcdab89 >+#define I2 0x98badcfe >+#define I3 0x10325476 >+#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ >+#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ >+/* C2 and C3 are from Knuth, The Art of Programming, Volume 2 >+** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. >+** Table 2, page 660. >+*/ >+ >+#define fs1 3 /* round 1 shift amounts */ >+#define fs2 7 >+#define fs3 11 >+#define fs4 19 >+#define gs1 3 /* round 2 shift amounts */ >+#define gs2 5 >+#define gs3 9 >+#define gs4 13 >+#define hs1 3 /* round 3 shift amounts */ >+#define hs2 9 >+#define hs3 11 >+#define hs4 15 >+ >+/* Compile-time macro declarations for MD4. >+** Note: The "rot" operator uses the variable "tmp". >+** It assumes tmp is declared as unsigned int, so that the >> >+** operator will shift in zeros rather than extending the sign bit. >+*/ >+#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) >+#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) >+#define h(X,Y,Z) (X^Y^Z) >+#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) >+#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) >+#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) >+#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) >+ >+/* MD4print(MDp) >+** Print message digest buffer MDp as 32 hexadecimal digits. >+** Order is from low-order byte of buffer[0] to high-order byte of >+** buffer[3]. >+** Each byte is printed with high-order hexadecimal digit first. >+** This is a user-callable routine. >+*/ >+void >+MD4Print(MDp) >+MD4_CTX *MDp; >+{ >+ int i,j; >+ for (i=0;i<4;i++) >+ for (j=0;j<32;j=j+8) >+ printf("%02x",(MDp->buffer[i]>>j) & 0xFF); >+} >+ >+/* MD4Init(MDp) >+** Initialize message digest buffer MDp. >+** This is a user-callable routine. >+*/ >+void >+MD4Init(MDp) >+MD4_CTX *MDp; >+{ >+ int i; >+ MDp->buffer[0] = I0; >+ MDp->buffer[1] = I1; >+ MDp->buffer[2] = I2; >+ MDp->buffer[3] = I3; >+ for (i=0;i<8;i++) MDp->count[i] = 0; >+ MDp->done = 0; >+} >+ >+/* MDblock(MDp,X) >+** Update message digest buffer MDp->buffer using 16-word data block X. >+** Assumes all 16 words of X are full of data. >+** Does not update MDp->count. >+** This routine is not user-callable. >+*/ >+static void >+MDblock(MDp,Xb) >+MD4_CTX *MDp; >+unsigned char *Xb; >+{ >+ register unsigned int tmp, A, B, C, D; >+ unsigned int X[16]; >+ int i; >+ >+ for (i = 0; i < 16; ++i) { >+ X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24); >+ Xb += 4; >+ } >+ >+ A = MDp->buffer[0]; >+ B = MDp->buffer[1]; >+ C = MDp->buffer[2]; >+ D = MDp->buffer[3]; >+ /* Update the message digest buffer */ >+ ff(A , B , C , D , 0 , fs1); /* Round 1 */ >+ ff(D , A , B , C , 1 , fs2); >+ ff(C , D , A , B , 2 , fs3); >+ ff(B , C , D , A , 3 , fs4); >+ ff(A , B , C , D , 4 , fs1); >+ ff(D , A , B , C , 5 , fs2); >+ ff(C , D , A , B , 6 , fs3); >+ ff(B , C , D , A , 7 , fs4); >+ ff(A , B , C , D , 8 , fs1); >+ ff(D , A , B , C , 9 , fs2); >+ ff(C , D , A , B , 10 , fs3); >+ ff(B , C , D , A , 11 , fs4); >+ ff(A , B , C , D , 12 , fs1); >+ ff(D , A , B , C , 13 , fs2); >+ ff(C , D , A , B , 14 , fs3); >+ ff(B , C , D , A , 15 , fs4); >+ gg(A , B , C , D , 0 , gs1); /* Round 2 */ >+ gg(D , A , B , C , 4 , gs2); >+ gg(C , D , A , B , 8 , gs3); >+ gg(B , C , D , A , 12 , gs4); >+ gg(A , B , C , D , 1 , gs1); >+ gg(D , A , B , C , 5 , gs2); >+ gg(C , D , A , B , 9 , gs3); >+ gg(B , C , D , A , 13 , gs4); >+ gg(A , B , C , D , 2 , gs1); >+ gg(D , A , B , C , 6 , gs2); >+ gg(C , D , A , B , 10 , gs3); >+ gg(B , C , D , A , 14 , gs4); >+ gg(A , B , C , D , 3 , gs1); >+ gg(D , A , B , C , 7 , gs2); >+ gg(C , D , A , B , 11 , gs3); >+ gg(B , C , D , A , 15 , gs4); >+ hh(A , B , C , D , 0 , hs1); /* Round 3 */ >+ hh(D , A , B , C , 8 , hs2); >+ hh(C , D , A , B , 4 , hs3); >+ hh(B , C , D , A , 12 , hs4); >+ hh(A , B , C , D , 2 , hs1); >+ hh(D , A , B , C , 10 , hs2); >+ hh(C , D , A , B , 6 , hs3); >+ hh(B , C , D , A , 14 , hs4); >+ hh(A , B , C , D , 1 , hs1); >+ hh(D , A , B , C , 9 , hs2); >+ hh(C , D , A , B , 5 , hs3); >+ hh(B , C , D , A , 13 , hs4); >+ hh(A , B , C , D , 3 , hs1); >+ hh(D , A , B , C , 11 , hs2); >+ hh(C , D , A , B , 7 , hs3); >+ hh(B , C , D , A , 15 , hs4); >+ MDp->buffer[0] += A; >+ MDp->buffer[1] += B; >+ MDp->buffer[2] += C; >+ MDp->buffer[3] += D; >+} >+ >+/* MD4Update(MDp,X,count) >+** Input: X -- a pointer to an array of unsigned characters. >+** count -- the number of bits of X to use. >+** (if not a multiple of 8, uses high bits of last byte.) >+** Update MDp using the number of bits of X given by count. >+** This is the basic input routine for an MD4 user. >+** The routine completes the MD computation when count < 512, so >+** every MD computation should end with one call to MD4Update with a >+** count less than 512. A call with count 0 will be ignored if the >+** MD has already been terminated (done != 0), so an extra call with >+** count 0 can be given as a "courtesy close" to force termination >+** if desired. >+*/ >+void >+MD4Update(MDp,X,count) >+MD4_CTX *MDp; >+unsigned char *X; >+unsigned int count; >+{ >+ unsigned int i, tmp, bit, byte, mask; >+ unsigned char XX[64]; >+ unsigned char *p; >+ >+ /* return with no error if this is a courtesy close with count >+ ** zero and MDp->done is true. >+ */ >+ if (count == 0 && MDp->done) return; >+ /* check to see if MD is already done and report error */ >+ if (MDp->done) >+ { printf("\nError: MD4Update MD already done."); return; } >+ >+ /* Add count to MDp->count */ >+ tmp = count; >+ p = MDp->count; >+ while (tmp) >+ { tmp += *p; >+ *p++ = tmp; >+ tmp = tmp >> 8; >+ } >+ >+ /* Process data */ >+ if (count == 512) >+ { /* Full block of data to handle */ >+ MDblock(MDp,X); >+ } >+ else if (count > 512) /* Check for count too large */ >+ { >+ printf("\nError: MD4Update called with illegal count value %d.", >+ count); >+ return; >+ } >+ else /* partial block -- must be last block so finish up */ >+ { >+ /* Find out how many bytes and residual bits there are */ >+ byte = count >> 3; >+ bit = count & 7; >+ /* Copy X into XX since we need to modify it */ >+ for (i=0;i<=byte;i++) XX[i] = X[i]; >+ for (i=byte+1;i<64;i++) XX[i] = 0; >+ /* Add padding '1' bit and low-order zeros in last byte */ >+ mask = 1 << (7 - bit); >+ XX[byte] = (XX[byte] | mask) & ~( mask - 1); >+ /* If room for bit count, finish up with this block */ >+ if (byte <= 55) >+ { >+ for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; >+ MDblock(MDp,XX); >+ } >+ else /* need to do two blocks to finish up */ >+ { >+ MDblock(MDp,XX); >+ for (i=0;i<56;i++) XX[i] = 0; >+ for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; >+ MDblock(MDp,XX); >+ } >+ /* Set flag saying we're done with MD computation */ >+ MDp->done = 1; >+ } >+} >+ >+/* >+** Finish up MD4 computation and return message digest. >+*/ >+void >+MD4Final(buf, MD) >+unsigned char *buf; >+MD4_CTX *MD; >+{ >+ int i, j; >+ unsigned int w; >+ >+ MD4Update(MD, NULL, 0); >+ for (i = 0; i < 4; ++i) { >+ w = MD->buffer[i]; >+ for (j = 0; j < 4; ++j) { >+ *buf++ = w; >+ w >>= 8; >+ } >+ } >+} >+ >+/* >+** End of md4.c >+****************************(cut)***********************************/ >diff -rPu pppd.old/md4.h pppd/md4.h >--- pppd.old/md4.h Thu Jan 1 03:00:00 1970 >+++ pppd/md4.h Sun Apr 5 09:02:21 1998 >@@ -0,0 +1,64 @@ >+ >+/* >+** ******************************************************************** >+** md4.h -- Header file for implementation of ** >+** MD4 Message Digest Algorithm ** >+** Updated: 2/13/90 by Ronald L. Rivest ** >+** (C) 1990 RSA Data Security, Inc. ** >+** ******************************************************************** >+*/ >+ >+#ifndef __P >+# if defined(__STDC__) || defined(__GNUC__) >+# define __P(x) x >+# else >+# define __P(x) () >+# endif >+#endif >+ >+ >+/* MDstruct is the data structure for a message digest computation. >+*/ >+typedef struct { >+ unsigned int buffer[4]; /* Holds 4-word result of MD computation */ >+ unsigned char count[8]; /* Number of bits processed so far */ >+ unsigned int done; /* Nonzero means MD computation finished */ >+} MD4_CTX; >+ >+/* MD4Init(MD4_CTX *) >+** Initialize the MD4_CTX prepatory to doing a message digest >+** computation. >+*/ >+extern void MD4Init __P((MD4_CTX *MD)); >+ >+/* MD4Update(MD,X,count) >+** Input: X -- a pointer to an array of unsigned characters. >+** count -- the number of bits of X to use (an unsigned int). >+** Updates MD using the first "count" bits of X. >+** The array pointed to by X is not modified. >+** If count is not a multiple of 8, MD4Update uses high bits of >+** last byte. >+** This is the basic input routine for a user. >+** The routine terminates the MD computation when count < 512, so >+** every MD computation should end with one call to MD4Update with a >+** count less than 512. Zero is OK for a count. >+*/ >+extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count)); >+ >+/* MD4Print(MD) >+** Prints message digest buffer MD as 32 hexadecimal digits. >+** Order is from low-order byte of buffer[0] to high-order byte >+** of buffer[3]. >+** Each byte is printed with high-order hexadecimal digit first. >+*/ >+extern void MD4Print __P((MD4_CTX *)); >+ >+/* MD4Final(buf, MD) >+** Returns message digest from MD and terminates the message >+** digest computation. >+*/ >+extern void MD4Final __P((unsigned char *, MD4_CTX *)); >+ >+/* >+** End of md4.h >+****************************(cut)***********************************/ >diff -rPu pppd.old/md5.h pppd/md5.h >--- pppd.old/md5.h Thu Jan 1 03:00:00 1970 >+++ pppd/md5.h Thu Jun 6 21:28:37 1996 >@@ -0,0 +1,73 @@ >+/* GLOBAL.H - RSAREF types and constants >+ */ >+ >+/* PROTOTYPES should be set to one if and only if the compiler supports >+ function argument prototyping. >+ The following makes PROTOTYPES default to 0 if it has not already >+ been defined with C compiler flags. >+ */ >+ >+#ifndef PROTOTYPES >+#define PROTOTYPES 0 >+#endif >+ >+/* POINTER defines a generic pointer type */ >+typedef unsigned char *POINTER; >+ >+/* UINT2 defines a two byte word */ >+typedef unsigned short int UINT2; >+ >+/* UINT4 defines a four byte word */ >+#if defined(__alpha) >+typedef unsigned int UINT4; >+#else >+typedef unsigned long int UINT4; >+#endif >+ >+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. >+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it >+ returns an empty list. >+ */ >+ >+#if PROTOTYPES >+#define PROTO_LIST(list) list >+#else >+#define PROTO_LIST(list) () >+#endif >+ >+/* MD5.H - header file for MD5C.C >+ */ >+ >+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All >+rights reserved. >+ >+License to copy and use this software is granted provided that it >+is identified as the "RSA Data Security, Inc. MD5 Message-Digest >+Algorithm" in all material mentioning or referencing this software >+or this function. >+ >+License is also granted to make and use derivative works provided >+that such works are identified as "derived from the RSA Data >+Security, Inc. MD5 Message-Digest Algorithm" in all material >+mentioning or referencing the derived work. >+ >+RSA Data Security, Inc. makes no representations concerning either >+the merchantability of this software or the suitability of this >+software for any particular purpose. It is provided "as is" >+without express or implied warranty of any kind. >+ >+These notices must be retained in any copies of any part of this >+documentation and/or software. >+ */ >+ >+/* MD5 context. */ >+typedef struct >+{ >+ UINT4 state[4]; /* state (ABCD) */ >+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ >+ unsigned char buffer[64]; /* input buffer */ >+} MD5_CTX; >+ >+void MD5Init PROTO_LIST ((MD5_CTX *)); >+void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); >+void MD5Final PROTO_LIST ((unsigned char[16], MD5_CTX *)); >diff -rPu pppd.old/options.c pppd/options.c >--- pppd.old/options.c Sun Aug 29 19:47:06 1999 >+++ pppd/options.c Wed Dec 8 12:45:48 1999 >@@ -58,6 +58,12 @@ > #include "ipxcp.h" > #endif /* IPX_CHANGE */ > >+#ifdef RADIUS >+#include "radius.h" >+#endif >+ >+int reqradius; >+ > #include <net/ppp_comp.h> > > #define FALSE 0 >@@ -148,6 +154,7 @@ > #ifdef OLD_OPTIONS > static int setupapfile __P((char **)); > #endif >+static int radiusauth __P((char **)); > static int nochap __P((char **)); > static int reqchap __P((char **)); > static int noaccomp __P((char **)); >@@ -294,6 +301,7 @@ > {"+pap", 0, reqpap}, /* Require PAP auth from peer */ > {"refuse-pap", 0, nopap}, /* Don't agree to auth to peer with PAP */ > {"-pap", 0, nopap}, /* Don't allow UPAP authentication with peer */ >+ {"radius", 0, radiusauth}, /* Require authentication on RADIUS server */ > {"require-chap", 0, reqchap}, /* Require CHAP authentication from peer */ > {"+chap", 0, reqchap}, /* Require CHAP authentication from peer */ > {"refuse-chap", 0, nochap}, /* Don't agree to auth to peer with CHAP */ >@@ -1372,6 +1380,17 @@ > lcp_wantoptions[0].neg_upap = 1; > setauth(NULL); > return 1; >+} >+ >+/* >+ * radiusauth - Sets reqradius variable to authenticate thru radius server >+ */ >+static int >+radiusauth(argv) >+ char **argv; >+{ >+ reqradius = 1; >+ return 1; > } > > #if OLD_OPTIONS >Binary files pppd.old/options.o and pppd/options.o differ >diff -rPu pppd.old/ppp.pam pppd/ppp.pam >--- pppd.old/ppp.pam Thu Jan 1 03:00:00 1970 >+++ pppd/ppp.pam Wed Feb 4 05:50:32 1998 >@@ -0,0 +1,6 @@ >+#%PAM-1.0 >+# Information for the PPPD process with the 'login' option. >+auth required /lib/security/pam_pwdb.so shadow nullok >+auth required /lib/security/pam_nologin.so >+account required /lib/security/pam_permit.so >+session required /lib/security/pam_permit.so >diff -rPu pppd.old/pppradius.c pppd/pppradius.c >--- pppd.old/pppradius.c Thu Jan 1 03:00:00 1970 >+++ pppd/pppradius.c Sat Dec 11 13:42:02 1999 >@@ -0,0 +1,394 @@ >+#include <sys/types.h> >+#include <sys/socket.h> >+#include <sys/param.h> >+#include <netinet/in.h> >+#include <sys/time.h> >+#include <sys/signal.h> >+#include <sys/termios.h> >+#ifdef SVR4 >+#include <sys/systeminfo.h> >+#endif /* SVR4 */ >+ >+#include <netdb.h> >+#include <pwd.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <time.h> >+#include <unistd.h> >+ >+#include "radius.h" >+ >+#ifndef RESPONSE_TIMEOUT >+#define RESPONSE_TIMEOUT 3 >+#endif >+ >+#ifndef MAX_RETRIES >+#define MAX_RETRIES 10 >+#endif >+ >+char recv_buffer[4096]; >+char send_buffer[4096]; >+char ourhostname[MAXHOSTNAMELEN]; >+char *progname; >+char *radius_dir; >+int debug_flag = 0; >+int dumpcore = 0; >+int file_logging = 2; /* 0 => syslog, 1 => logfile, 2 => stderr */ >+int zap_logfile = 0; >+int authfile_cnt = 0; >+int clients_cnt = 0; >+int users_cnt = 0; >+time_t birthdate; >+AATVPTR rad_authen_aatv = (AATV *) NULL; >+AATVPTR rad_ipc_aatv = (AATV *) NULL; >+AATV *authtype_tv[PW_AUTH_MAX + 1]; >+FILE *ddt = NULL; >+FILE *msgfd = stderr; >+extern void dir_init(); >+ >+static void radpwtst_usage (); >+ >+typedef struct string_list_struct >+{ >+ struct string_list_struct *next; >+ char *str; >+}string_list; >+ >+int RADIUS_port; >+int RADIUS_asi; >+int RADIUS_data; >+time_t RADIUS_bt; >+time_t RADIUS_et; >+char *RADIUS_name; >+ >+int rad_auth(char *name, char *password) >+{ >+ int result; >+ int retries; >+ int new_old; >+ char *client_name = (char *)NULL; >+ char *clear_pw = (char *)NULL; >+ string_list *vplist = NULL; >+ string_list **vpnext = &vplist; >+ char msg[4096]; >+ char passwd[AUTH_PASS_LEN + 1]; >+ SEND_DATA data; >+ int send_server(); >+ >+ syslog(LOG_DAEMON, "Trying to authenticate: %s with password: %s\n", name, password); >+ >+ data.code = PW_ACCESS_REQUEST; >+ data.svc_port = 1645; >+ data.server = "ns.link-ul.ru"; >+ radius_dir = "/var/adm/raddb"; >+ data.timeout = RESPONSE_TIMEOUT; >+ data.user_file = (char *)NULL; >+ data.group = (char *)NULL; >+ data.send_pairs = (VALUE_PAIR *)NULL; >+ >+ retries = MAX_RETRIES; >+ new_old = 0; >+ data.ustype=PW_FRAMED; >+ data.fptype=PW_PPP; >+ data.port_num = RADIUS_port; >+ >+ *vpnext = (string_list *)malloc(sizeof(string_list)); >+ (*vpnext)->str = "NAS-Port-Type=0"; >+ (*vpnext)->next = (string_list *)NULL; >+ vpnext = &((*vpnext)->next); >+ data.user_name = name; >+ data.password = password; >+ >+ dir_init(); >+ >+ if (dict_init() != 0) { >+ fprintf(stderr, "Missing directory in /var/adm/raddb\n"); >+ exit(-1); >+ } >+ for ( ; vplist ; vplist = vplist->next) { >+ if (pair_parse (vplist->str, &data.send_pairs) != 0) { >+ fprintf (stderr, >+ "%s: Invalid attribute-value pair, '%s'\n", >+ progname, vplist->str); >+ exit(-1); >+ } >+ } >+ data.seq_nbr = RADIUS_data = (u_char) rand(); >+ if (gethostname(ourhostname, sizeof(ourhostname)) < 0) { >+ perror("gethostname"); >+ exit(-1); >+ } >+ if (client_name == (char *)NULL) { >+ if ((data.client_id = get_ipaddr(ourhostname)) == 0) { >+ printf("Couldn't get own IP address!\n"); >+ data.client_id = 0; >+ } >+ } else >+ data.client_id = get_ipaddr(client_name); >+ if ((data.user_file != (char *)NULL)&&(data.group == (char *)NULL)) >+ data.group = "DEFAULT"; >+ msg[0] = '\0'; >+ result = send_server(&data, &retries, msg); >+ if (result == OK_RC) { >+ printf("\"%s\" authentication OK", data.user_name); >+ RADIUS_name = (char *)malloc(strlen(data.user_name)+1); >+ strcpy(RADIUS_name, data.user_name); >+ } else { >+ printf("\"%s\" authentication failed", data.user_name); >+ if (result != BADRESP_RC) >+ printf("(RC=%i)", result); >+ } >+ if (msg[0]) >+ printf(": %s", msg); >+ putchar('\n'); >+ >+ return (result); >+} >+ >+int rad_acct_start(char *name) >+{ >+ >+ int result; >+ int retries; >+ int new_old; >+ char *client_name = (char *)NULL; >+ char *clear_pw = (char *)NULL; >+ string_list *vplist = NULL; >+ string_list **vpnext = &vplist; >+ char msg[4096]; >+ char passwd[AUTH_PASS_LEN + 1]; >+ SEND_DATA data; >+ int send_server(); >+ char *str; >+ >+ data.code = PW_ACCOUNTING_REQUEST; >+ data.svc_port = 1646; >+ data.server = "ns.link-ul.ru"; >+ radius_dir = "/var/adm/raddb"; >+ data.timeout = RESPONSE_TIMEOUT; >+ data.user_file = (char *)NULL; >+ data.group = (char *)NULL; >+ data.send_pairs = (VALUE_PAIR *)NULL; >+ retries = MAX_RETRIES; >+ new_old = 0; >+ data.ustype = PW_FRAMED; >+ data.fptype = PW_PPP; >+ data.port_num = RADIUS_port; >+ data.user_name = name; >+ data.password = ""; >+ >+ if (pair_parse("NAS-Port-Type=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute-value pair\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Status-Type=1", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-status-type\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Authentic=3", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-authentic\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Delay-Time=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-delay-time\n"); >+ exit(-1); >+ } >+ >+ str = (char *)malloc(128); >+ RADIUS_asi = rand(); >+ sprintf(str, "Acct-Session-Id=%x", RADIUS_asi); >+ if (pair_parse(str, &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-session-id\n"); >+ exit(-1); >+ } >+ >+ dir_init(); >+ if (dict_init() != 0) { >+ fprintf(stderr, "Missing directory in /var/adm/raddb\n"); >+ exit(-1); >+ } >+ >+ data.seq_nbr = (++RADIUS_data); >+ if (gethostname(ourhostname, sizeof(ourhostname)) < 0) { >+ perror("gethostname"); >+ exit(-1); >+ } >+ if (client_name == (char *)NULL) { >+ if ((data.client_id = get_ipaddr(ourhostname)) == 0) { >+ printf("Couldn't get own IP address!\n"); >+ data.client_id = 0; >+ } >+ } else >+ data.client_id = get_ipaddr(client_name); >+ if ((data.user_file != (char *)NULL)&&(data.group == (char *)NULL)) >+ data.group = "DEFAULT"; >+ msg[0] = '\0'; >+ result = send_server(&data, &retries, msg); >+ >+ if (result == OK_RC) >+ printf("\"%s\" accounting start OK", data.user_name); >+ else { >+ printf("\"%s\" accounting start failed", data.user_name); >+ if (result != BADRESP_RC) >+ printf("(RC=%i)", result); >+ } >+ if (msg[0]) >+ printf(": %s", msg); >+ putchar('\n'); >+ >+ RADIUS_bt = time(NULL); >+ >+ return (result); >+} >+ >+int rad_acct_stop(char *name) >+{ >+ int result; >+ int retries; >+ int new_old; >+ char *client_name = (char *)NULL; >+ char *clear_pw = (char *)NULL; >+ string_list *vplist = NULL; >+ string_list **vpnext = &vplist; >+ char msg[4096]; >+ char passwd[AUTH_PASS_LEN + 1]; >+ SEND_DATA data; >+ int send_server(); >+ char *str; >+ >+ data.code = PW_ACCOUNTING_REQUEST; >+ data.svc_port = 1646; >+ data.server = "ns.link-ul.ru"; >+ radius_dir = "/var/adm/raddb"; >+ data.timeout = RESPONSE_TIMEOUT; >+ data.user_file = (char *)NULL; >+ data.group = (char *)NULL; >+ data.send_pairs = (VALUE_PAIR *)NULL; >+ retries = MAX_RETRIES; >+ new_old = 0; >+ data.ustype = PW_FRAMED; >+ data.fptype = PW_PPP; >+ data.port_num = RADIUS_port; >+ data.user_name = name; >+ data.password = ""; >+ >+ if (pair_parse("NAS-Port-Type=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute-value pair\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Status-Type=2", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-status-type\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Authentic=3", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-authentic\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Delay-Time=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-delay-time\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Output-Octets=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-output-octets\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Input-Octets=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-inpute-octets\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Input-Packets=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute aÓÓt-inpute-packets\n"); >+ exit(-1); >+ } >+ >+ if (pair_parse("Acct-Output-Packets=0", &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-output-packets\n"); >+ exit(-1); >+ } >+ >+ str = (char *)malloc(128); >+ sprintf(str,"Acct-Session-Id=%x", RADIUS_asi); >+ if (pair_parse(str, &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-session-id\n"); >+ exit(-1); >+ } >+ >+ RADIUS_et = time(NULL); >+ sprintf(str,"Acct-Session-Time=%ld",RADIUS_et-RADIUS_bt); >+ if (pair_parse(str, &data.send_pairs) != 0) { >+ fprintf(stderr, "Invalid attribute acct-session-time\n"); >+ exit(-1); >+ } >+ >+ dir_init(); >+ if (dict_init() != 0) { >+ fprintf(stderr, "Missing directory in /var/adm/raddb\n"); >+ exit(-1); >+ } >+ >+ data.seq_nbr = (++RADIUS_data); >+ if (gethostname(ourhostname, sizeof(ourhostname)) < 0) { >+ perror("gethostname"); >+ exit(-1); >+ } >+ if (client_name == (char *)NULL) { >+ if ((data.client_id = get_ipaddr(ourhostname)) == 0) { >+ printf("Couldn't get own IP address!\n"); >+ data.client_id = 0; >+ } >+ } else >+ data.client_id = get_ipaddr(client_name); >+ if ((data.user_file != (char *)NULL)&&(data.group == (char *)NULL)) >+ data.group = "DEFAULT"; >+ msg[0] = '\0'; >+ result = send_server(&data, &retries, msg); >+ if (result == OK_RC) >+ printf("\"%s\" accounting stop OK", data.user_name); >+ else { >+ printf("\"%s\" accounting stop failed", data.user_name); >+ if (result != BADRESP_RC) >+ printf("(RC=%i)", result); >+ } >+ if (msg[0]) >+ printf(": %s", msg); >+ putchar('\n'); >+ >+ return (result); >+} >+ >+#if 0 >+int main (int argc, char *argv[]) >+{ >+ progname = *argv; >+ srand(time(0)); >+ RADIUS_port = rand(); >+ >+ if (argc != 3) >+ radpwtst_usage(); >+ if (authenticate(argv[1], argv[2]) != OK_RC) >+ exit(-1); >+ if (accounting_start(argv[1]) != OK_RC) >+ exit(-1); >+ printf("Press any key to finish\n"); >+ getchar(); >+ if (accounting_stop(argv[1]) != OK_RC) >+ exit(-1); >+} /* end of main () */ >+ >+static void >+radpwtst_usage () >+ >+{ >+ printf ("Usage: %s username password\n", progname); >+ exit (-1); >+} /* end of radpwtst_usage () */ >+#endif >diff -rPu pppd.old/rad_dict.c pppd/rad_dict.c >--- pppd.old/rad_dict.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_dict.c Wed May 22 17:54:06 1996 >@@ -0,0 +1,365 @@ >+/* >+ * >+ * 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. >+ * >+ * Public entry points in this file: >+ * >+ * dict_attrfind >+ * dict_attrget >+ * dict_init >+ * dict_valfind >+ * dict_valget >+ * >+ */ >+ >+static char sccsid[] = >+ "@(#)dict.c 1.2 Copyright 1992 Livingston Enterprises Inc"; >+ >+static char rcsid[] = "$Id: dict.c,v 1.9 1996/05/17 14:19:03 web Exp $"; >+ >+#include <stdio.h> >+#include <stdlib.h> >+#include <time.h> >+#include <sys/types.h> >+#include <ctype.h> >+#include <netinet/in.h> >+#include <syslog.h> >+ >+#include "radius.h" >+ >+extern int debug_flag; >+extern char *radius_dir; >+ >+static DICT_ATTR *dictionary_attributes; >+static DICT_VALUE *dictionary_values; >+ >+/************************************************************************* >+ * >+ * Function: dict_init >+ * >+ * Purpose: Initialize the dictionary. Read all ATTRIBUTES into >+ * the dictionary_attributes list. Read all VALUES into >+ * the dictionary_values list. >+ * >+ *************************************************************************/ >+ >+int >+dict_init () >+ >+{ >+ FILE *dictfd; >+ char dummystr[AUTH_ID_LEN]; >+ char namestr[AUTH_ID_LEN]; >+ char valstr[AUTH_ID_LEN]; >+ char attrstr[AUTH_ID_LEN]; >+ char typestr[AUTH_ID_LEN]; >+ int line_no; >+ DICT_ATTR *attr; >+ DICT_VALUE *dval; >+ char buffer[256]; >+ int value; >+ int type; >+ static char *func = "dict_init"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ sprintf (buffer, "%s/%s", radius_dir, RADIUS_DICTIONARY); >+ if ((dictfd = fopen (buffer, "r")) == (FILE *) NULL) >+ { >+ fprintf (stderr, "%s: Couldn't open dictionary: %s\n", >+ func, buffer); >+ return (-1); >+ } >+ >+ line_no = 0; >+ while (fgets (buffer, sizeof (buffer), dictfd) != (char *) NULL) >+ { >+ line_no++; >+ >+ /* Skip empty space */ >+ if (*buffer == '#' || *buffer == '\0' || *buffer == '\n') >+ { >+ continue; >+ } >+ >+ if (strncmp (buffer, "ATTRIBUTE", 9) == 0) >+ { >+ >+ /* Read the ATTRIBUTE line */ >+ if (sscanf (buffer, "%s%s%s%s", dummystr, namestr, >+ valstr, typestr) != 4) >+ { >+ fprintf (stderr, >+ "%s: Invalid attribute on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ /* >+ * Validate all entries >+ */ >+ if (strlen (namestr) > NAME_LENGTH) >+ { >+ fprintf (stderr, >+ "%s: Invalid name length on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ if (!isdigit (*valstr)) >+ { >+ fprintf (stderr, >+ "%s: Invalid value on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ value = atoi (valstr); >+ >+ if (strcmp (typestr, "string") == 0) >+ { >+ type = PW_TYPE_STRING; >+ } >+ else if (strcmp (typestr, "integer") == 0) >+ { >+ type = PW_TYPE_INTEGER; >+ } >+ else if (strcmp (typestr, "ipaddr") == 0) >+ { >+ type = PW_TYPE_IPADDR; >+ } >+ else if (strcmp (typestr, "date") == 0) >+ { >+ type = PW_TYPE_DATE; >+ } >+ else if (strcmp (typestr, "octets") == 0) >+ { >+ type = PW_TYPE_OCTETS; >+ } >+ else if (strcmp (typestr, "vendor") == 0) >+ { >+ type = PW_TYPE_VENDOR; >+ } >+ else >+ { >+ fprintf (stderr, >+ "%s: Invalid type on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ /* Create a new attribute for the list */ >+ if ((attr = >+ (DICT_ATTR *) malloc (sizeof (DICT_ATTR))) >+ == (DICT_ATTR *) NULL) >+ { >+ fprintf (stderr, "%s: FATAL out of memory\n", >+ func); >+ abort (); >+ } >+ strcpy (attr->name, namestr); >+ attr->value = value; >+ attr->type = type; >+ >+ /* Insert it into the list */ >+ attr->next = dictionary_attributes; >+ dictionary_attributes = attr; >+ } >+ else if (strncmp (buffer, "VALUE", 5) == 0) >+ { >+ /* Read the VALUE line */ >+ if (sscanf (buffer, "%s%s%s%s", dummystr, attrstr, >+ namestr, valstr) != 4) >+ { >+ fprintf (stderr, >+ "%s: Invalid value entry on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ /* >+ * Validate all entries >+ */ >+ if (strlen (attrstr) > NAME_LENGTH) >+ { >+ fprintf (stderr, >+ "%s: Invalid attribute length on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ if (strlen (namestr) > NAME_LENGTH) >+ { >+ fprintf (stderr, >+ "%s: Invalid name length on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ >+ if (!isdigit (*valstr)) >+ { >+ fprintf (stderr, >+ "%s: Invalid value on line %d of dictionary\n", >+ func, line_no); >+ return (-1); >+ } >+ value = atoi (valstr); >+ >+ /* Create a new VALUE entry for the list */ >+ if ((dval = >+ (DICT_VALUE *) malloc (sizeof (DICT_VALUE))) >+ == (DICT_VALUE *) NULL) >+ { >+ fprintf (stderr, "%s: FATAL out of memory\n", >+ func); >+ abort (); >+ } >+ strcpy (dval->attrname, attrstr); >+ strcpy (dval->name, namestr); >+ dval->value = value; >+ >+ /* Insert it into the list */ >+ dval->next = dictionary_values; >+ dictionary_values = dval; >+ } >+ } >+ fclose (dictfd); >+ return (0); >+} /* end of dict_init () */ >+ >+/************************************************************************* >+ * >+ * Function: dict_attrget >+ * >+ * Purpose: Return the full attribute structure based on the >+ * attribute id number. >+ * >+ *************************************************************************/ >+ >+DICT_ATTR * >+dict_attrget (attribute) >+ >+int attribute; >+ >+{ >+ DICT_ATTR *attr; >+ >+ attr = dictionary_attributes; >+ while (attr != (DICT_ATTR *) NULL) >+ { >+ if (attr->value == attribute) >+ { >+ return (attr); >+ } >+ attr = attr->next; >+ } >+ return ((DICT_ATTR *) NULL); >+} /* end of dict_attrget () */ >+ >+/************************************************************************* >+ * >+ * Function: dict_attrfind >+ * >+ * Purpose: Return the full attribute structure based on the >+ * attribute name. >+ * >+ *************************************************************************/ >+ >+DICT_ATTR * >+dict_attrfind (attrname) >+ >+char *attrname; >+{ >+ DICT_ATTR *attr; >+ >+ attr = dictionary_attributes; >+ while (attr != (DICT_ATTR *) NULL) >+ { >+ if (strcasecmp (attr->name, attrname) == 0) >+ { >+ return (attr); >+ } >+ attr = attr->next; >+ } >+ return ((DICT_ATTR *) NULL); >+} /* end of dict_attrfind () */ >+ >+/************************************************************************* >+ * >+ * Function: dict_valfind >+ * >+ * Purpose: Return the full value structure based on the >+ * value name. >+ * >+ *************************************************************************/ >+ >+DICT_VALUE * >+dict_valfind (valname) >+ >+char *valname; >+ >+{ >+ DICT_VALUE *val; >+ >+ val = dictionary_values; >+ while (val != (DICT_VALUE *) NULL) >+ { >+ if (strcasecmp (val->name, valname) == 0) >+ { >+ return (val); >+ } >+ val = val->next; >+ } >+ return ((DICT_VALUE *) NULL); >+} /* end of dict_valfind () */ >+ >+/************************************************************************* >+ * >+ * Function: dict_valget >+ * >+ * Purpose: Return the full value structure based on the >+ * actual value and the associated attribute name. >+ * >+ *************************************************************************/ >+ >+DICT_VALUE * >+dict_valget (value, attrname) >+ >+UINT4 value; >+char *attrname; >+ >+{ >+ DICT_VALUE *val; >+ >+ val = dictionary_values; >+ while (val != (DICT_VALUE *) NULL) >+ { >+ if (strcmp (val->attrname, attrname) == 0 && >+ val->value == value) >+ { >+ return (val); >+ } >+ val = val->next; >+ } >+ return ((DICT_VALUE *) NULL); >+} /* end of dict_valget () */ >diff -rPu pppd.old/rad_funcs.c pppd/rad_funcs.c >--- pppd.old/rad_funcs.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_funcs.c Tue Apr 29 21:20:56 1997 >@@ -0,0 +1,2269 @@ >+/* >+ * RADIUS -- Remote Authentication Dial In User Service >+ * >+ * COPYRIGHT (c) 1992, 1993, 1994, 1995, 1996 >+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INCORPORATED >+ * ALL RIGHTS RESERVED >+ * >+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE >+ * THIS SOFTWARE AND SUCH DERIVATIVE WORKS IN BINARY FORM ONLY FOR ANY PURPOSE, >+ * SO LONG AS NO FEE IS CHARGED, AND SO LONG AS THE COPYRIGHT NOTICE ABOVE, THIS >+ * GRANT OF PERMISSION, AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND >+ * SO LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY >+ * ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR DISTRIBUTION OF THIS >+ * SOFTWARE WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. >+ * >+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY >+ * OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE >+ * UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING >+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE >+ * LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR >+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN >+ * CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER >+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. >+ * >+ * For a License to distribute source code or to charge a fee for the program >+ * or a product containing the program, contact MERIT at the University of >+ * Michigan: >+ * >+ * aaa-license@merit.edu >+ * >+ * [This version puts NO LIMITS on the use. It grants the right to create >+ * DERIVATIVE WORKS. The user may copy and distribute the code in the form >+ * received AND DERIVATIVE WORKS, so long as no fee is charged. If copies are >+ * made, our copyright notice and the disclaimer must be included on them. USE >+ * THIS VERSION WITH CARE. THIS VERSION VERY LIKELY WILL KILL ANY POTENTIAL >+ * FOR LATER COMMERCIALIZATION OF THE SOFTWARE.] >+ * >+ * >+ * Public entry points in this file: >+ * >+ * add_string >+ * authtype_toa >+ * avpair_add >+ * avpair_assign >+ * avpair_copy >+ * avpair_get >+ * avpair_new >+ * avpair_vtoa >+ * compress_file >+ * debug_list >+ * debug_pair >+ * dumpit >+ * fprint_attr_val >+ * gen_valpairs >+ * get_errmsg >+ * get_passwd >+ * get_vp >+ * get_last_vp >+ * insert_vp >+ * loghead >+ * logit >+ * missing_attribute >+ * parse_realm >+ * prune_pairs >+ * _reply_message >+ * reply_sprintf >+ * setupsock >+ * trunc_logfile >+ * type_string >+ * >+ */ >+ >+static char rcsid[] = "$Id: funcs.c,v 1.99 1996/06/14 16:14:47 web Exp $"; >+ >+#include <sys/types.h> >+#include <sys/param.h> >+ >+#if defined(sys5) >+#include <sys/sysmacros.h> >+#endif /* sys5 */ >+ >+#include <sys/socket.h> >+#include <sys/time.h> >+ >+#if defined(aix) || defined(ultrix) >+#include <fcntl.h> >+#else /* aix */ >+#include <sys/fcntl.h> >+#endif /* aix */ >+ >+#include <sys/wait.h> >+#include <net/if.h> >+#include <netinet/in.h> >+#include <arpa/inet.h> >+ >+#include <stdio.h> >+#include <netdb.h> >+#include <time.h> >+#include <ctype.h> >+#include <errno.h> >+#include <dirent.h> >+#include <syslog.h> >+#include <unistd.h> >+#include <varargs.h> >+ >+#include "radius.h" >+ >+extern int debug_flag; >+extern int dumpcore; >+extern int file_logging; >+extern int spawn_flag; >+extern int zap_logfile; >+ >+#if !defined(__FreeBSD__) && !defined(_BSDI_VERSION) && !defined(__NetBSD__) >+extern int sys_nerr; >+extern char *sys_errlist[]; >+#endif /* __FreeBSD__ */ >+ >+extern FILE *ddt; >+extern FILE *msgfd; >+extern char *radius_dir; >+extern AATVPTR rad_authen_aatv; >+extern time_t birthdate; >+extern char recv_buffer[4096]; >+extern char send_buffer[4096]; >+extern char ourhostname[MAXHOSTNAMELEN]; >+ >+/************************************************************************* >+ * >+ * Function: add_string (string, convert) >+ * >+ * Purpose: Store string in storage block, returning pointer. >+ * Optimizes string storage allocation and allows only >+ * one copy of string to be stored. A NULL string pointer >+ * returns a pointer to a null string. >+ * >+ * If convert is non-zero, the string is stored in lower-case. >+ * Thus a case insensitive match is performed to attempt to >+ * find an already existing copy of the string in the table. >+ * >+ * Use this only to store non-dynamic (i.e., configuration) >+ * strings as there is no way to delete strings and lookups >+ * to see if a string is already is present are quite >+ * inefficient. >+ * >+ *************************************************************************/ >+ >+char * >+add_string (string, convert) >+ >+char *string; >+int convert; >+ >+{ >+ typedef struct char_blk >+ { >+ struct char_blk *next; >+ char *next_ptr; >+ int rem_len; >+ char strings[2048]; >+ } CHAR_BLK; >+ >+ static CHAR_BLK *first_blk = (CHAR_BLK *) NULL; >+ CHAR_BLK *last_blk; >+ CHAR_BLK *blk; >+ CHAR_BLK *space_blk; /* 1st block with sufficient space */ >+ register char *ptr; >+ register char *fptr; >+ register char *str; >+ register UINT4 len; >+ register UINT4 slen; >+ char lcstr[AUTH_ID_LEN]; /* Case converted string */ >+ static char *func = "add_string"; >+ >+ if (!string) >+ { >+ string = ""; /* Convert NULL pointer to null string */ >+ } >+ >+ /* Copy input to all lowercase */ >+ if (convert & ASLC) >+ { >+ for (ptr = lcstr, fptr = string ; *fptr ; ) >+ { >+ *ptr++ = tolower (*fptr++); >+ } >+ *ptr++ = '\0'; >+ len = ptr - lcstr; >+ string = lcstr; >+ } >+ else >+ { >+ len = strlen (string) + 1; >+ } >+ >+ space_blk = (CHAR_BLK *) NULL; >+ >+ /* See if we're already storing this string */ >+ for (blk = last_blk = first_blk ; blk ; last_blk = blk, blk = blk->next) >+ { >+ for (str = blk->strings ; str < blk->next_ptr ; str += slen) >+ { >+ if (len > (slen = (UINT4) *str++)) >+ { >+ continue; >+ } >+ >+ fptr = slen - len + str; >+ ptr = string; >+ while (*ptr++ == *fptr) >+ { >+ if (*fptr++ == '\0') /* Found it! */ >+ { >+ return fptr - len; >+ } >+ } >+ } >+ if (space_blk == (CHAR_BLK *) NULL && blk->rem_len > len) >+ { >+ space_blk = blk; >+ } >+ } >+ >+ if (convert & FINDONLY) >+ { >+ return NULL; >+ } >+ >+ /* Need to store new string. See if we found space in previous block */ >+ if (space_blk == (CHAR_BLK *) NULL) >+ { >+ if ((blk = (CHAR_BLK *) malloc (sizeof(CHAR_BLK))) >+ == (CHAR_BLK *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL couldn't allocate CHAR_BLK storage", >+ func); >+ abort (); >+ } >+ blk->next_ptr = blk->strings; >+ blk->rem_len = sizeof (blk->strings); >+ blk->next = (CHAR_BLK *) NULL; >+ if (last_blk == (CHAR_BLK *) NULL) >+ { >+ first_blk = blk; >+ } >+ else >+ { >+ last_blk->next = blk; >+ } >+ space_blk = blk; >+ } >+ fptr = space_blk->next_ptr; >+ *fptr++ = len; >+ strcpy (fptr, string); >+ space_blk->next_ptr = fptr + len; >+ space_blk->rem_len -= len + 1; >+ return fptr; >+} /* end of add_string () */ >+ >+/****************************************************************************** >+ * >+ * Function: authtype_toa >+ * >+ * Purpose: Return a string representation of the authreq code. >+ * >+ * Returns: pointer to static string. >+ * >+ *****************************************************************************/ >+ >+char * >+authtype_toa (code) >+ >+int code; /* code indicating authen, acct, etc. */ >+ >+{ >+ static char *typelist[] = >+ { >+ "invalid(0)", /* invalid */ >+ "access", /* PW_ACCESS_REQUEST */ >+ "accept", /* PW_ACCESS_ACCEPT */ >+ "reject", /* PW_ACCESS_REJECT */ >+ "acct-req", /* PW_ACCOUNTING_REQUEST */ >+ "acct-resp", /* PW_ACCOUNTING_RESPONSE */ >+ "acct-status", /* PW_ACCOUNTING_STATUS */ >+ "pw-request", /* PW_PASSWORD_REQUEST */ >+ "pw-ack", /* PW_PASSWORD_ACK */ >+ "pw-reject", /* PW_PASSWORD_REJECT */ >+ "acct-msg", /* PW_ACCOUNTING_MESSAGE */ >+ "access-challenge", /* PW_ACCESS_CHALLENGE */ >+ "status-server", /* PW_STATUS_SERVER */ >+ "status-client" /* PW_STATUS_CLIENT */ >+ }; >+ static char unknown[20]; >+ >+ if ((code <= 0) || ((sizeof (typelist) / sizeof (typelist[0])) <= code)) >+ { >+ if (code == PW_FORWARDING) >+ { >+ return "forwarding"; >+ } >+ >+ sprintf (unknown, "invalid(%d)", code); >+ return unknown; >+ } >+ >+ return typelist[code]; >+} /* end of authtype_toa () */ >+ >+/****************************************************************************** >+ * >+ * Function: avpair_add >+ * >+ * Purpose: Add an attribute-value pair to the given list. >+ * >+ * Returns: pointer to added a/v pair upon success, >+ * NULL pointer upon failure. >+ * >+ * Remarks: Always appends the new pair to the end of the list. >+ * >+ *****************************************************************************/ >+ >+VALUE_PAIR * >+avpair_add (list, attrid, pval, len) >+ >+VALUE_PAIR **list; /* a list of attribute-value pairs. */ >+int attrid; /* Attribute id number. */ >+void *pval; /* Pointer to value. */ >+int len; /* length of value, or 0 */ >+ >+{ >+ VALUE_PAIR *vp; >+ >+ vp = avpair_new (attrid, pval, len); >+ >+ if (vp != (VALUE_PAIR *) NULL) >+ { >+ insert_vp (list, (VALUE_PAIR *) NULL, vp); >+ } >+ >+ return vp; >+ >+} /* end of avpair_add */ >+ >+/****************************************************************************** >+ * >+ * Function: avpair_assign >+ * >+ * Purpose: Assign the given raw value to an attribute-value pair. >+ * >+ * Returns: 0 on success, >+ * -1 on failure. >+ * >+ *****************************************************************************/ >+ >+int >+avpair_assign (vp, pval, len) >+ >+VALUE_PAIR *vp; /* pointer to the attribute-value pair */ >+void *pval; /* pointer to value to be assigned */ >+int len; /* for strings: */ >+ /* len == 0 ==> null-terminated ASCII string */ >+ /* len > 0 ==> len is length of raw binary data */ >+ /* for non-strings: */ >+ /* len == 0 ==> just plain data, just gets copied */ >+ /* len > 0 ==> convert data from network ... */ >+ /* ... representation before copying */ >+ >+{ >+ int result = -1; >+ static char *func = "avpair_assign"; >+ >+ if (len < 0 || len > AUTH_STRING_LEN) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: bad attribute length %d", >+ func, len); >+ } >+ else >+ { >+ switch (vp->type) >+ { >+ case PW_TYPE_STRING: /* Use lvalue field to store length. */ >+ case PW_TYPE_OCTETS: >+ case PW_TYPE_VENDOR: >+ if (len > 0) /* use length to control the raw copy */ >+ { >+ memcpy (vp->strvalue, (char *) pval, len); >+ vp->strvalue[len] = 0; /* In case of string! */ >+ vp->lvalue = len; >+ } >+ else /* len == 0 means the string is NULL terminated */ >+ { >+ strncpy (vp->strvalue, (char *) pval, >+ AUTH_STRING_LEN); >+ vp->lvalue = strlen ((char *) pval); >+ } >+ result = 0; >+ break; >+ >+ case PW_TYPE_DATE: >+ case PW_TYPE_INTEGER: >+ case PW_TYPE_IPADDR: >+ if (len > 0) /* need to convert the raw network value */ >+ { >+ vp->lvalue = ntohl(* (UINT4 *) pval); >+ } >+ else /* len == 0 indicates just plain data */ >+ { >+ memcpy (&vp->lvalue, pval, sizeof (vp->lvalue)); >+ } >+ *vp->strvalue = '\0'; /* Insure null for type IPADDR */ >+ result = 0; >+ break; >+ >+ default: >+ dprintf(1, (LOG_DAEMON, LOG_DEBUG, >+ "%s: Unknown attribute %d", func, vp->type)); >+ } >+ } >+ return result; >+} /* end of avpair_assign () */ >+ >+/****************************************************************************** >+ * >+ * Function: avpair_copy >+ * >+ * Purpose: Copy a specified attribute-value pair from one given >+ * list to another. >+ * >+ * Returns: 0 if the attribute-value pair doesn't exist in the source list, >+ * 1 (non-zero) if the attribute-value pair is copied. >+ * >+ ****************************************************************************** >+ */ >+ >+int >+avpair_copy (pdst, psrc, attr) >+ >+VALUE_PAIR **pdst; >+VALUE_PAIR *psrc; >+int attr; >+ >+{ >+ VALUE_PAIR *pvp; >+ VALUE_PAIR *pnew; >+ static char *func = "avpair_copy"; >+ >+ if ((pvp = get_vp (psrc, attr)) == (VALUE_PAIR *) NULL) >+ { >+ return 0; >+ } >+ >+ if ((pnew = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) >+ == (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, "%s: FATAL out of memory", func); >+ abort (); >+ } >+ >+ memcpy ((char *) pnew, (char *) pvp, sizeof (VALUE_PAIR)); >+ pnew->next = (VALUE_PAIR *) NULL; >+ insert_vp (pdst, (VALUE_PAIR *) NULL, pnew); >+ >+ return 1; >+} /* end of avpair_copy () */ >+ >+/******************************************************************************* >+ * >+ * Function: avpair_get >+ * >+ * Purpose: Find specified a/v pair from a list and return its value. >+ * >+ * Returns: Type of the attribute on success (look at PW_TYPE_*), >+ * or -1 on failure. >+ * >+ ******************************************************************************/ >+ >+int >+avpair_get (pval, vplist, attrid) >+ >+void *pval; /* OUT: buffer for returning value */ >+VALUE_PAIR *vplist; /* pointer to list of attribute-value pairs */ >+int attrid; /* attribute to find */ >+ >+{ >+ VALUE_PAIR *vp; >+ static char *func = "avpair_get"; >+ >+ vp = get_vp (vplist, attrid); >+ if (vp == (VALUE_PAIR *) NULL) >+ { >+ return (-1); >+ } >+ >+ switch (vp->type) >+ { >+ case PW_TYPE_STRING: >+ strcpy ((char *) pval, vp->strvalue); >+ break; >+ >+ case PW_TYPE_OCTETS: >+ case PW_TYPE_VENDOR: >+ memcpy ((char *) pval, vp->strvalue, vp->lvalue); >+ break; >+ >+ case PW_TYPE_DATE: >+ case PW_TYPE_INTEGER: >+ case PW_TYPE_IPADDR: >+ *((UINT4 *) pval) = vp->lvalue; >+ break; >+ >+ default: >+ dprintf(1, (LOG_DAEMON, LOG_DEBUG, >+ "%s: Unknown attribute %d", func, vp->type)); >+ } >+ return vp->type; >+} /* end of avpair_get () */ >+ >+/****************************************************************************** >+ * >+ * Function: avpair_new >+ * >+ * Purpose: Make an new attribute-value pair with given parameters. >+ * >+ * Returns: Pointer to generated a/v pair when successful, >+ * NULL when failure. >+ * >+ *****************************************************************************/ >+ >+VALUE_PAIR * >+avpair_new (attrid, pval, len) >+ >+int attrid; /* integer id number of the attribute */ >+void *pval; /* pointer to value */ >+int len; /* length of value, or 0 */ >+ >+{ >+ VALUE_PAIR *vp = (VALUE_PAIR *) NULL; >+ DICT_ATTR *pda; >+ static char *func = "avpair_new"; >+ >+ if ((pda = dict_attrget (attrid)) == (DICT_ATTR *) NULL) >+ { >+ dprintf(1, (LOG_DAEMON, LOG_DEBUG, >+ "%s: Unknown attribute %d", func, attrid)); >+ } >+ else >+ { >+ if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) >+ != (VALUE_PAIR *) NULL) >+ { >+ strncpy (vp->name, pda->name, sizeof (vp->name)); >+ vp->attribute = attrid; >+ vp->next = (VALUE_PAIR *) NULL; >+ vp->type = pda->type; >+ if (avpair_assign (vp, pval, len) == 0) >+ { >+ return vp; >+ } >+ free (vp); >+ vp = (VALUE_PAIR *) NULL; >+ } >+ else >+ { >+ logit (LOG_DAEMON, LOG_ALERT, "%s: FATAL out of memory", >+ func); >+ abort (); >+ } >+ } >+ return vp; >+} /* end of avpair_new () */ >+ >+#define MAX_AVPAIR_VTOA 20 >+ >+/************************************************************************* >+ * >+ * Function: avpair_vtoa >+ * >+ * Purpose: Produce a string representation of the value of a pair. >+ * >+ *************************************************************************/ >+ >+char * >+avpair_vtoa (vp, sws) >+ >+VALUE_PAIR *vp; >+int sws; >+ >+{ >+ int max; >+ int pos; >+ UINT4 num; >+ char *c; >+ char *p; >+ DICT_VALUE *dval; >+ struct in_addr inad; >+ static char buffers[MAX_AVPAIR_VTOA][1024]; >+ static int ndx = 0; >+ char *buff = buffers[ndx]; >+ static char *func = "avpair_vtoa"; >+ >+ if (vp == (VALUE_PAIR *) NULL) >+ { >+ if ((sws & AVPAIR_VTOA_NULL) != 0) >+ { >+ return ""; >+ } >+ return NULL; >+ } >+ >+ ndx++; >+ if (ndx > MAX_AVPAIR_VTOA) >+ { >+ ndx = 0; >+ } >+ >+ switch (vp->type) >+ { >+ case PW_TYPE_STRING: >+ p = (char *) buff; >+ c = vp->strvalue; >+ >+ if ((sws & AVPAIR_VTOA_QUOTE) != 0) >+ { >+ *p++ = '\''; >+ } >+ >+ max = vp->lvalue; >+ if (max == 0) >+ { >+ dprintf(2, (LOG_DAEMON, LOG_DEBUG, >+ "%s: Using strlen() for vp 0x%p {type=%d, attr=%d}", >+ func, vp, vp->type, vp->attribute)); >+ max = strlen (vp->strvalue); >+ } >+ >+ pos = 0; >+ for (pos = 0; pos < max; pos++) >+ { >+ if (c[pos] == '\0') >+ { >+ break; >+ } >+ >+ switch (c[pos]) >+ { >+ case '\b': /* BACKSPACE */ >+ *p++ = '\\'; >+ *p++ = 'b'; >+ break; >+ >+ case '\r': /* Carriage Return */ >+ *p++ = '\\'; >+ *p++ = 'r'; >+ break; >+ >+ case '\n': /* Newline / Line feed */ >+ *p++ = '\\'; >+ *p++ = 'n'; >+ break; >+ >+ case '\t': /* Horizontal tab */ >+ *p++ = '\\'; >+ *p++ = 't'; >+ break; >+ >+ case '\\': /* Self-escape */ >+ *p++ = '\\'; >+ *p++ = '\\'; >+ break; >+ >+ case '\'': /* Quote-escape */ >+ *p++ = '\\'; >+ *p++ = '\''; >+ break; >+ >+ default: >+ if ((' ' <= c[pos]) && (c[pos] < 0x7f)) >+ { >+ *p++ = c[pos]; >+ } >+ else >+ { >+ char tmp[10]; >+ >+ if (c[pos] == 0) >+ { >+ strcpy (p, "\\0"); >+ } >+ else >+ { >+ sprintf (tmp, "\\x%2.2x", >+ (unsigned char) c[pos]); >+ strcpy (p, tmp); >+ } >+ p += strlen (p); >+ } >+ } >+ } /* for each character... */ >+ >+ if ((sws & AVPAIR_VTOA_QUOTE) != 0) >+ { >+ *p++ = '\''; >+ } >+ >+ *p = '\0'; >+ >+ break; >+ >+ case PW_TYPE_INTEGER: >+ dval = dict_valget (vp->lvalue, vp->name); >+ if (dval != (DICT_VALUE *) NULL) >+ { >+ strcpy (buff, dval->name); >+ } >+ else >+ { >+#if defined(__alpha) >+ sprintf (buff, "%d", vp->lvalue); >+#else /* defined(alpha) */ >+ sprintf (buff, "%ld", vp->lvalue); >+#endif /* defined(alpha) */ >+ } >+ break; >+ >+ case PW_TYPE_IPADDR: >+ inad.s_addr = htonl(vp->lvalue); >+ strcpy (buff, inet_ntoa (inad)); >+ break; >+ >+ case PW_TYPE_DATE: >+ strftime (buff, sizeof (buff), "%b %e %Y", >+ gmtime ((time_t *) & vp->lvalue)); >+ break; >+ >+ >+ case PW_TYPE_OCTETS: >+ strcpy (buff, "0x"); >+ p = (char *) buff; >+ p += strlen (buff); >+ c = vp->strvalue; >+ >+ for (pos = 0; pos < vp->lvalue; pos++) >+ { >+ char tmp[3]; >+ >+ sprintf (tmp, "%2.2x", c[pos]); >+ strcpy (p, tmp); >+ if (pos % 4 == 3) >+ { >+ strcat (p, " "); >+ } >+ p += strlen (p); >+ } >+ *p = '\0'; >+ break; >+ >+ case PW_TYPE_VENDOR: >+ c = vp->strvalue; >+ if (*c != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Invalid vendor-specific code, 0x%x", func, *c); >+ return NULL; >+ } >+ memcpy ((char *) &num, c, 4); >+ pos = ntohl(num); >+ >+ sprintf (buff, "v%d-", pos); >+ for (pos = 4; pos < vp->lvalue; pos++) >+ { >+ char tmp[3]; >+ >+ sprintf (tmp, "%2.2x", c[pos]); >+ strcpy (p, tmp); >+ p += strlen (p); >+ } >+ *p = '\0'; >+ break; >+ >+ default: >+ if (sws & AVPAIR_VTOA_NULL) >+ { >+ return ""; >+ } >+ return NULL; >+ } /* switch (vp) */ >+ >+return buff; >+ >+} /* end of avpair_vtoa () */ >+ >+/************************************************************************* >+ * >+ * Function: compress_file >+ * >+ * Purpose: Compress and reopen a file. >+ * >+ *************************************************************************/ >+ >+void >+compress_file (fd, fname) >+ >+FILE **fd; >+char *fname; >+ >+{ >+ int pid; >+ struct tm *clock; >+ time_t now; >+ char today[80]; >+ char name[128]; >+ char newname[128]; >+ static char *func = "compress_file"; >+ >+ now = time (0); >+ now -= 86400; /* the archived log is for yesterday! */ >+ sprintf (name, "%s/%s", radius_dir, fname); >+ clock = localtime (&now); >+ strftime (today, 15, "%y%m%d", clock); >+ sprintf (newname, "%s/%s.%s", radius_dir, fname, today); >+ if (link (name, newname) < 0) /* get another handle */ >+ { >+ return; >+ } >+ >+ if (unlink (name) < 0) >+ { >+ return; >+ } >+ >+ sync (); /* update disk metadata */ >+ >+ fclose (*fd); >+ >+ if ((*fd = fopen (name, "w")) == (FILE *) NULL) >+ { >+ return; >+ } >+ >+ now += 86400; /* correct the time now */ >+ strcpy (today, ctime (&now)); >+ fprintf (*fd, >+ "%-24.24s: created by PID %u Version %s up since %-24.24s\n", >+ today, getpid (), RADIUS_VERSION, ctime (&birthdate)); >+#ifndef SCO >+ fchmod (fileno (*fd), 0644); >+#endif /* SCO */ >+ >+ if (spawn_flag > 0) /* only compress if we won't block */ >+ { >+ pid = (int) fork (); >+ if (pid < 0) /* error */ >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: fork: %s", func, get_errmsg ()); >+ exit (-5); >+ } >+ if (pid > 0) /* parent */ >+ { >+ return; >+ } >+ else /* in child */ >+ { >+ execl (RADIUS_COMPRESS, RADIUS_COMPRESS, >+ newname, (char *) NULL); >+ exit (0); >+ } >+ } >+ >+ return; >+} /* end of compress_file () */ >+ >+/************************************************************************* >+ * >+ * Function: debug_list >+ * >+ * Purpose: Print the value pair list to the desired File. >+ * >+ *************************************************************************/ >+ >+void >+debug_list (fd, pair) >+ >+FILE *fd; >+VALUE_PAIR *pair; >+ >+{ >+ VALUE_PAIR *vp; >+ >+ if (debug_flag) >+ { >+ if (ddt) >+ { >+ fd = ddt; >+ } >+ >+ vp = pair; >+ >+ while (vp != (VALUE_PAIR *) NULL) >+ { >+ debug_pair (fd, vp); >+ vp = vp->next; >+ } >+ } >+ return; >+} /* end of debug_list () */ >+ >+/************************************************************************* >+ * >+ * Function: debug_pair >+ * >+ * Purpose: Print the Attribute-value pair to the desired File. >+ * >+ *************************************************************************/ >+ >+void >+debug_pair (fd, pair) >+ >+FILE *fd; >+VALUE_PAIR *pair; >+ >+{ >+ if (debug_flag) >+ { >+ if (ddt) >+ { >+ fd = ddt; >+ } >+ >+ fputs (" ", fd); >+ fprint_attr_val (fd, pair); >+ fputs ("\n", fd); >+ } >+ return; >+} /* end of debug_pair () */ >+ >+/************************************************************************* >+ * >+ * Function: dumpit >+ * >+ * Purpose: Dump the memory area using logit() >+ * >+ * Usage: dumpit (facility, level, ptr, ptrlen, offset, format, args, ...); >+ * >+ * Where facility and level are found in syslog.h and the >+ * format is just a printf-style format string using the args. >+ * >+ *************************************************************************/ >+ >+int >+dumpit (facility, level, ptr, ptrlen, offset, format, va_alist) >+ >+int facility; /* Logging facility, see dprintf() */ >+int level; /* Logging level, see dprintf() */ >+char *ptr; /* Pointer to start of dumping region. */ >+unsigned int ptrlen; /* Length of the region to dump. */ >+unsigned int offset; /* Offset from "ptr" to where to start dump. */ >+char *format; /* A sprintf() like format string. */ >+va_dcl /* Arguments for sprintf() string. */ >+ >+{ >+ va_list pvar; >+ int done; >+ >+ static char buffer[MAXPATHLEN]; /* Work area. */ >+ >+ va_start (pvar); >+ vsprintf (buffer, format, pvar); >+ va_end (pvar); >+ >+ if (strlen (buffer) > 0) >+ { >+ logit (facility, level, "%s", buffer); >+ } >+ >+ logit (facility, level, "Hex dump at 0x%p/%x for %d bytes", ptr, offset, >+ ptrlen); >+ >+ while (ptrlen > 0) >+ { >+ done = hex_dump (buffer, ptr, ptrlen, offset); >+ ptrlen -= done; >+ offset += done; >+ ptr += done; >+ logit (facility, level, "%s", buffer); >+ } >+ >+ return 0; >+ >+} /* end of dumpit () */ >+ >+void >+fprint_attr_val (fd, pair) >+ >+FILE *fd; >+VALUE_PAIR *pair; >+ >+{ >+ char *val; >+ >+ if (pair->name[0] == '\0') >+ { >+ return; >+ } >+ >+ if ((val = avpair_vtoa (pair, 0)) != (char *) NULL) >+ { >+ fprintf (fd, "%s = %s", pair->name, val); >+ } >+ else >+ { >+ fprintf (fd, "%s is unknown", pair->name); >+ } >+ >+ return; >+ >+} /* end of fprint_attr_val () */ >+ >+/************************************************************************* >+ * >+ * Function: gen_valpairs >+ * >+ * Purpose: Takes attribute/value pairs from buffer and builds a >+ * value_pair list using allocated memory. >+ * >+ *************************************************************************/ >+ >+VALUE_PAIR * >+gen_valpairs (auth) >+ >+AUTH_HDR *auth; >+ >+{ >+ int attribute; >+ int attrlen; >+ int bad_packet = 0; /* Set to one if bad packet rec'v'd. */ >+ int len; >+ UINT4 lvalue; >+ u_char *ptr; >+ DICT_ATTR *attr; >+ VALUE_PAIR *vp; >+ VALUE_PAIR *pair; >+ static char *func = "gen_valpairs"; >+ >+ dprintf(2, (LOG_DAEMON, LOG_DEBUG, "%s: entered", func)); >+ >+ /* >+ * Extract attribute-value pairs >+ */ >+ ptr = auth->data; >+ len = ntohs(auth->length) - AUTH_HDR_LEN; /* length of attributes */ >+ vp = (VALUE_PAIR *) NULL; >+ >+ while (len > 0) >+ { >+ attribute = *ptr++; >+ attrlen = *ptr++; >+ attrlen -= 2; >+ if (attrlen < 0 || attrlen > AUTH_STRING_LEN || attrlen > len) >+ { >+ dumpit (LOG_DAEMON, LOG_ERR, ptr, attrlen, 0, >+ "Received attribute %d with invalid length %d", >+ attribute, attrlen); >+ bad_packet = 1; >+ break; >+ } >+ >+ if ((attr = dict_attrget (attribute)) == (DICT_ATTR *) NULL) >+ { >+ ddumpx(1, (LOG_DAEMON, LOG_DEBUG, ptr, attrlen, 0, >+ "Received unknown attribute %d of length %d", >+ attribute, attrlen)); >+ bad_packet = 1; >+ } >+ else >+ { >+ if ((pair = >+ (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) == >+ (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL out of memory", func); >+ abort (); >+ } >+ strcpy (pair->name, attr->name); >+ pair->attribute = attr->value; >+ pair->type = attr->type; >+ pair->next = (VALUE_PAIR *) NULL; >+ >+ switch (attr->type) >+ { >+ >+ case PW_TYPE_STRING: >+ case PW_TYPE_OCTETS: >+ case PW_TYPE_VENDOR: >+ memcpy (pair->strvalue, (char *) ptr, attrlen); >+ pair->strvalue[attrlen] = '\0'; >+ pair->lvalue = attrlen; >+ debug_pair (stdout, pair); >+ insert_vp (&vp, (VALUE_PAIR *) NULL, pair); >+ break; >+ >+ case PW_TYPE_INTEGER: >+ case PW_TYPE_IPADDR: >+ memcpy ((char *) &lvalue, (char *) ptr, >+ sizeof (UINT4)); >+ pair->lvalue = ntohl(lvalue); >+ *pair->strvalue = '\0'; /* zap DNS for IPADDR */ >+ debug_pair (stdout, pair); >+ insert_vp (&vp, (VALUE_PAIR *) NULL, pair); >+ break; >+ >+ default: >+ dprintf(1, (LOG_DAEMON, LOG_DEBUG, >+ " %s (Unknown Type)", attr->name)); >+ free (pair); >+ break; >+ } >+ >+ } >+ ptr += attrlen; >+ len -= attrlen + 2; >+ } >+ >+ if (bad_packet) >+ { >+ ddumpx(1, (LOG_DAEMON, LOG_DEBUG, auth->data, >+ ntohs(auth->length) - AUTH_HDR_LEN, 0, >+ "Dump of entire bad packet")); >+ } >+ >+ return (vp); >+} /* end of gen_valpairs () */ >+ >+/************************************************************************* >+ * >+ * Function: get_errmsg >+ * >+ * Purpose: Return pointer to static string which gives complete >+ * filesystem error message. >+ * >+ *************************************************************************/ >+ >+char * >+get_errmsg () >+ >+{ >+ static char errmsg[80]; >+ >+ if (errno < sys_nerr) >+ { >+ return (char *) sys_errlist[errno]; >+ } >+ else >+ { >+ sprintf (errmsg, "Error %d", errno); >+ return errmsg; >+ } >+} /* end of get_errmsg () */ >+ >+/****************************************************************************** >+ * >+ * Function: get_passwd >+ * >+ * Purpose: Decrypts password contained in the PW_USER_PASSWORD or >+ * PW_ENCRYPTED_PASSWORD value-pair in the AUTH_REQ queue >+ * entry. Tries to match one of these passwords against >+ * the "user_secret", if the "user_secret" is not a NULL >+ * pointer. Will also perform a CHAP authentication check, >+ * if the PW_CHAP_PASSWORD value-pair is found in the request >+ * and "user_secret" is provided. >+ * >+ * Returns: 2 to indicate CHAP failure, >+ * 1 to indicate PASSWORD match failure, >+ * 0 to indicate success, >+ * -1 if no PASSWORD or CHAP value-pair is present. >+ * >+ ******************************************************************************/ >+ >+int >+get_passwd (authreq, pw, user_secret, salt) >+ >+AUTH_REQ *authreq; /* Pointer to authentication request. */ >+char *pw; /* Receives decrypted password. */ >+ /* (If NULL, only CHAP is attempted.) */ >+char *user_secret; /* Secret we share with this user or */ >+ /* NULL. If NULL, CHAP is not allowed */ >+ /* and the password match check is not */ >+ /* performed */ >+char *salt; /* Encryption salt. If this and the */ >+ /* user_secret are both non-NULL, then */ >+ /* crypt() is called to encrypt the */ >+ /* password before attempting to match */ >+ /* the user_secret or the check CHAP */ >+ /* reply.*/ >+ >+{ >+ VALUE_PAIR *item; >+ u_char buffer[AUTH_PASS_LEN + AUTH_VECTOR_LEN + 1]; >+ int i; >+ int secretlen; >+ int result; >+ u_char digest[CHAP_VALUE_LENGTH]; >+ u_char *ptr; >+ char *crypt (); >+ static char *func = "get_passwd"; >+ >+ dprintf(3, (LOG_DAEMON, LOG_DEBUG, "%s: entered", func)); >+ >+ if (pw != NULL && >+ (item = get_vp (authreq->request, PW_USER_PASSWORD)) >+ != (VALUE_PAIR *) NULL) >+ { >+ /* Use the secret to setup the decryption digest */ >+ secretlen = strlen ((char *) authreq->secret); >+ strcpy ((char *) buffer, (char *) authreq->secret); >+ memcpy ((char *) buffer + secretlen, (char *) authreq->vector, >+ AUTH_VECTOR_LEN); >+ md5_calc (digest, buffer, secretlen + AUTH_VECTOR_LEN); >+ memcpy (pw, item->strvalue, AUTH_PASS_LEN); >+ for (i = 0; i < AUTH_PASS_LEN; i++) >+ { >+ pw[i] ^= digest[i]; >+ } >+ pw[AUTH_PASS_LEN] = '\0'; /* thanks to billw@cisco.com */ >+ result = 0; >+ if (user_secret != (char *) NULL) >+ { >+ if (salt != (char *) NULL) >+ { >+ pw = crypt (pw, salt); >+ } >+ >+ if ((result = strcmp (pw, user_secret)) != 0) >+ { >+ result = 1; /* Indicate pw match failure */ >+ } >+ } >+ } >+ else if (user_secret != (char *) NULL && >+ (item = get_vp (authreq->request, PW_CHAP_PASSWORD)) >+ != (VALUE_PAIR *) NULL) >+ { >+ /* Use MD5 to verify CHAP */ >+ ptr = buffer; >+ *ptr++ = *item->strvalue; >+ strcpy ((char *) ptr, user_secret); >+ >+ /* >+ * Allow for CHAP using an encrypted password. (The client >+ * encrypts the password before generating the CHAP challenge >+ * reply.) This lets CHAP be used even when passwords are >+ * stored in an encrypted form. No clients provide this >+ * capability yet, but they could start doing so now! >+ */ >+ >+ if (salt != (char *) NULL) >+ { >+ ptr = (u_char *) crypt ((char *) ptr, salt); >+ } >+ >+ secretlen = strlen ((char *) ptr); >+ ptr += secretlen; >+ memcpy ((char *) ptr, (char *) authreq->vector, >+ AUTH_VECTOR_LEN); >+ md5_calc (digest, buffer, >+ 1 + CHAP_VALUE_LENGTH + secretlen); >+ /* Compare them */ >+ if ((result = memcmp ((char *) digest, item->strvalue + 1, >+ CHAP_VALUE_LENGTH)) != 0) >+ { >+ result = 2; /* Indicate CHAP failure */ >+ } >+ >+ } >+ else >+ { >+ if (pw) >+ *pw = '\0'; /* Return null as pw */ >+ result = -1; /* -1 indicates no PW or CHAP vp in request */ >+ } >+ return (result); >+} /* end of get_passwd () */ >+ >+/************************************************************************* >+* >+* Function: get_last_vp >+* >+* Purpose: Find the last attribute value-pair (which matches the specified >+* attribute) from the specified value-pair list. >+* >+*************************************************************************/ >+ >+VALUE_PAIR * >+get_last_vp (vp, attr) >+ >+VALUE_PAIR *vp; >+UINT4 attr; >+ >+{ >+ VALUE_PAIR *last_vp; >+ >+ /* >+ * Find the first matching value-pair. >+ */ >+ >+ for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next) >+ { >+ continue; >+ } >+ >+ /* >+ * If we run off the end of the list, return a NULL. >+ */ >+ if (vp == (VALUE_PAIR *) NULL) >+ { >+ return (VALUE_PAIR *) NULL; >+ } >+ >+ /* >+ * Scan the remainder of the list for a match. >+ * If we found a match, return it. >+ */ >+ last_vp = get_last_vp (vp->next, attr); >+ >+ if (last_vp != (VALUE_PAIR *) NULL) >+ { >+ return (last_vp); >+ } >+ >+ /* If didn't find a match, return the one we found above. */ >+ return (vp); >+ >+} /* end of get_last_vp () */ >+ >+/************************************************************************* >+* >+* Function: get_vp >+* >+* Purpose: Find the first attribute value-pair (which matches the given >+* attribute) from the specified value-pair list. >+* >+*************************************************************************/ >+ >+VALUE_PAIR * >+get_vp (vp, attr) >+ >+VALUE_PAIR *vp; >+UINT4 attr; >+ >+{ >+ for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next) >+ { >+ continue; >+ } >+ >+ return (vp); >+} /* end of get_vp () */ >+ >+/************************************************************************* >+ * >+ * Function: hex_dump >+ * >+ * Purpose: Format a region of octets into a formatted string >+ * suitable for displaying that region of memory. >+ * >+ *************************************************************************/ >+ >+int >+hex_dump (buffer, data, len, offset) >+ >+char *buffer; >+char *data; >+int len; >+int offset; >+ >+{ >+ int i = 0; >+ int j = 0; >+ int size = 0; >+ int wlen = 0; >+ char hex[3]; /* a hex string placeholder. */ >+ unsigned char *start = (unsigned char *) data; >+ >+ if ((!buffer) || (!data) || (len <= 0)) >+ { >+ return -1; >+ } >+ >+ sprintf (buffer, "0x%p:", data); >+ >+ buffer += strlen (buffer); >+ if (offset >= 0) >+ { >+ sprintf (buffer, " 0x%4.4x|", offset); >+ buffer += strlen (buffer); >+ } >+ >+ if (len > 16) >+ { >+ len = 16; >+ } >+ >+ /* Dump the data in hexadecimal. */ >+ >+ for (i = 0; i < len; i += 4) >+ { >+ wlen = i + 4; >+ if (wlen > len) >+ { >+ wlen = len; >+ } >+ >+ strcat (buffer, " "); >+ buffer++; >+ for ( j = i; j < wlen; j++) >+ { >+ sprintf (hex, "%2.2X", *start++); >+ strcat (buffer, hex); >+ buffer += 2; >+ size++; >+ } >+ >+ for ( ; j < (i + 4) ; j++) >+ { >+ strcat (buffer, ".."); >+ buffer += 2; >+ } >+ } >+ >+ for ( ; i < 16 ; i += 4) >+ { >+ strcat (buffer, " ........"); >+ buffer += 9; >+ } >+ >+ /* Dump the data in ASCII. */ >+ >+ strcat (buffer, "| |"); >+ buffer += strlen (buffer); >+ for (i = 0; i < len; i++) >+ { >+ if ((' ' <= *data) && (*data < 0x7f)) >+ { >+ *buffer++ = *data; >+ } >+ else >+ { >+ *buffer++ = '.'; >+ } >+ data++; >+ } >+ >+ for ( ; i < 16 ; i++) >+ { >+ *buffer++ = '|'; >+ } >+ >+ *buffer++ = '|'; >+ *buffer = '\0'; /* Terminate the string. */ >+ >+ return size; >+ >+} /* end of hex_dump () */ >+ >+/************************************************************************* >+ * >+ * Function: insert_vp >+ * >+ * Purpose: Given the address of an existing list "a" and a pointer >+ * to an entry "p" in that list, add the value pair "b" to >+ * the "a" list after the "p" entry. If "p" is NULL, add >+ * the value pair "b" to the end of "a". >+ * >+ *************************************************************************/ >+ >+void >+insert_vp (a, p, b) >+ >+VALUE_PAIR **a; >+VALUE_PAIR *p; >+VALUE_PAIR *b; >+ >+{ >+ VALUE_PAIR *this_node; >+ VALUE_PAIR *vp; >+ static char *func = "insert_vp"; >+ >+ if (b->next != (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL value pair (0x%p) next ptr. (0x%p) not NULL", >+ func, b, b->next); >+ dumpcore = 1; >+ abort (); >+ } >+ >+ if (*a == (VALUE_PAIR *) NULL) >+ { >+ *a = b; >+ return; >+ } >+ >+ vp = *a; >+ >+ if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */ >+ { >+ while (vp != (VALUE_PAIR *) NULL) >+ { >+ this_node = vp; >+ vp = vp->next; >+ } >+ } >+ else /* look for the "p" entry in the "a" list */ >+ { >+ this_node = *a; >+ while (this_node != (VALUE_PAIR *) NULL) >+ { >+ if (this_node == p) >+ { >+ break; >+ } >+ this_node = this_node->next; >+ } >+ } >+ >+ b->next = this_node->next; >+ this_node->next = b; >+ >+ return; >+} /* end of insert_vp () */ >+ >+/************************************************************************* >+ * >+ * Function: logit >+ * >+ * Purpose: Log the provided error message to the error logging facility. >+ * >+ * Usage: logit (facility, level, format, args, ...); >+ * >+ * Where facility and level are found in syslog.h and the >+ * format is just a printf-style format string using the args. >+ * >+ *************************************************************************/ >+ >+int >+logit (va_alist) >+ >+va_dcl >+ >+{ >+ va_list pvar; >+ int priority; >+ int facility; >+ int level; >+ char *format; >+ time_t timeval; >+ char filename[MAXPATHLEN]; >+ static char buffer[MAXPATHLEN]; >+ static char *func = "logit"; >+ >+ va_start (pvar); >+ facility = va_arg (pvar, int); >+ level = va_arg (pvar, int); >+ format = va_arg (pvar, char *); >+ vsprintf (buffer, format, pvar); >+ va_end (pvar); >+ >+ if (file_logging == 1) /* log it to the logfile */ >+ { >+ if (msgfd == stderr) >+ { >+ msgfd = (FILE *) NULL; >+ } >+ >+ if (msgfd == (FILE *) NULL) >+ { >+ sprintf (filename, "%s", RADIUS_LOG); >+ msgfd = fopen (filename, "a"); >+ >+ if (msgfd == (FILE *) NULL) >+ { >+ fprintf (stderr, >+ "%s: Couldn't open %s for logging\n", >+ func, filename); >+ msgfd = stderr; >+ } >+ } >+ >+ if (level != LOG_DEBUG) /* don't log debugging messages */ >+ { >+ timeval = time (0); >+ fprintf (msgfd, "%-24.24s: %s\n", >+ ctime (&timeval), buffer); >+ >+ if (level == LOG_ALERT) >+ { >+ fflush (msgfd); >+ } >+ } >+ } >+ else /* was not logging to a file */ >+ { >+ if (file_logging == 2) /* log it to stderr */ >+ { >+ fprintf (msgfd, "%s\n", buffer); >+ } >+ else /* log it to syslog(3) */ >+ { >+ zap_logfile = 0; >+ priority = facility | level; >+ syslog (priority, "%s", buffer); >+ } >+ } >+ >+ if (level == LOG_DEBUG && ddt != (FILE *) NULL) >+ { >+ fprintf (ddt, "%s\n", buffer); /* log it to pre-opened device */ >+ } >+ >+ return 0; >+} /* end of logit () */ >+ >+/****************************************************************************** >+ * >+ * Function: loghead >+ * >+ * Purpose: Write a header in a logfile if it is empty. This function >+ * guarantees the header is only written once at the very >+ * beginning of the file. >+ * >+ * Usage: loghead (file, format, args, ...); >+ * >+ * Where file is a FILE pointer to an open file and the >+ * format is just a printf style format string using the args. >+ * >+ *****************************************************************************/ >+ >+int >+loghead (va_alist) >+ >+va_dcl >+ >+{ >+ va_list pvar; >+ int fd; >+ char *format; >+ FILE *fp; >+ struct flock lck; >+ >+ va_start (pvar); >+ fp = va_arg (pvar, FILE *); >+ fd = fileno (fp); >+ lck.l_type = F_WRLCK; >+ lck.l_whence = 0; >+ lck.l_start = SEEK_SET; >+ lck.l_len = 0L; >+ lck.l_pid = (pid_t) 0; >+ fcntl (fd, F_SETLKW, lck); >+ if (lseek (fd, 0L, SEEK_CUR) == (off_t) 0L) >+ { >+ format = va_arg (pvar, char *); >+ vfprintf (fp, format, pvar); >+ va_end (pvar); >+ } >+ lck.l_type = F_UNLCK; >+ fcntl (fd, F_SETLK, lck); >+ return 0; >+} /* end of loghead () */ >+ >+/************************************************************************* >+ * >+ * Function: missing_attribute >+ * >+ * Purpose: Generate standard log message for missing attributes. >+ * >+ *************************************************************************/ >+ >+void >+missing_attribute (authreq, func, attribute, etc) >+ >+AUTH_REQ *authreq; >+char *func; /* Function which called us. */ >+int attribute; /* Missing attribute. */ >+char *etc; /* Optional additional information. */ >+ >+{ >+ VALUE_PAIR *vp; >+ DICT_ATTR *attr = dict_attrget (attribute); >+ char *attr_name; >+ char unknown_attr[20]; >+ >+ if (attr != (DICT_ATTR *) NULL) >+ { >+ attr_name = attr->name; /* Mark name. */ >+ } >+ else >+ { >+ sprintf (unknown_attr, "unknown(%d)", attribute); >+ attr_name = unknown_attr; >+ } >+ >+ /* Get NAS-Identifier or IP address. */ >+ if ((vp = get_vp (authreq->cur_request, PW_NAS_IDENTIFIER)) >+ == (VALUE_PAIR *) NULL) >+ { >+ vp = get_vp (authreq->cur_request, PW_NAS_IP_ADDRESS); >+ } >+ >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s:* MISSING %s (%d) in %s (type %d) request %d from %s via. %s[%d] %s", >+ func, attr_name, attribute, authtype_toa (authreq->code), >+ authreq->code, authreq->id, >+ (vp == (VALUE_PAIR *) NULL) ? "?" : avpair_vtoa (vp, 0), >+ ip_hostname (authreq->ipaddr), authreq->udp_port, >+ (etc == (char *) NULL) ? "" : etc); >+ return; >+} /* end of missing_attribute () */ >+ >+/************************************************************************* >+ * >+ * Function: parse_realm >+ * >+ * Purpose: Split user entered string found in PW_USER_NAME into >+ * the PW_USER_ID and PW_USER_REALM a/v pairs and hang >+ * them both on both the authreq->request and the >+ * authreq->cur_request lists for later use. >+ * >+ * Returns: pointer to the realm a/v pair, >+ * NULL otherwise. >+ * >+ *************************************************************************/ >+ >+VALUE_PAIR * >+parse_realm (authreq) >+ >+AUTH_REQ *authreq; >+ >+{ >+ int count; >+ int type; >+ VALUE_PAIR *vp; >+ VALUE_PAIR **vp_prev; >+ DICT_ATTR *attr; >+ char *agent; >+ char *filter; >+ char *pos; >+ char *realm; >+ char *u_realm; >+ char *userid; >+ char name[AUTH_ID_LEN + 1]; >+ static char *func = "parse_realm"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if ((vp = get_vp (authreq->cur_request, PW_USER_REALM)) >+ != (VALUE_PAIR *) NULL) >+ { >+ return vp; /* It's already there, so just return it! */ >+ } >+ >+ if ((vp = get_vp (authreq->cur_request, PW_USER_ID)) >+ == (VALUE_PAIR *) NULL) >+ { >+ return vp; /* The PW_USER_ID must be there to parse! */ >+ } >+ >+ /* Make a local copy of the name. */ >+ strncpy (name, vp->strvalue, AUTH_ID_LEN); >+ name[AUTH_ID_LEN] = '\0'; /* Guarantee a null terminated string. */ >+ >+ if ((pos = strchr (name, '@')) != (char *) NULL) /* Is the '@' style. */ >+ { >+ if ((userid = strtok (name, "@")) == (char *) NULL) >+ { >+ return (VALUE_PAIR *) NULL; /* Can't use a null name. */ >+ } >+ if ((u_realm = strtok (NULL, "")) == (char *) NULL) >+ { >+ u_realm = ""; >+ } >+ } >+ else /* There was no '@' in the User-Id. */ >+ { >+ if ((pos = strchr (name, '/')) != (char *) NULL) /* '/' style */ >+ { >+ if ((u_realm = strtok (name, "/")) == (char *) NULL) >+ { >+ u_realm = ""; >+ } >+ if ((userid = strtok (NULL, "")) == (char *) NULL) >+ { >+ return (VALUE_PAIR *) NULL; /* Name was null. */ >+ } >+ } >+ else /* There was neither '@' nor '/' in the User-Id. */ >+ { >+ userid = name; >+ u_realm = ""; >+ } >+ } >+ >+ /* Check for null user id. */ >+ if ((userid == (char *) NULL) || (*userid == '\0')) >+ { >+ return (VALUE_PAIR *) NULL; /* Name was null. */ >+ } >+ >+ strcpy (vp->strvalue, userid); /* Modify the existing value... */ >+ vp->lvalue = strlen (vp->strvalue); /* and set length correctly. */ >+ >+ /* Next, build the realm a/v pair. */ >+ if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) >+ == (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL out of memory", func); >+ abort (); >+ } >+ >+ attr = dict_attrget (PW_USER_REALM); >+ strcpy (vp->name, attr->name); >+ vp->attribute = attr->value; >+ vp->type = attr->type; >+ vp->next = (VALUE_PAIR *) NULL; >+ >+ if ((u_realm == (char *) NULL) || (u_realm[0] == '\0')) >+ { >+ vp->strvalue[0] = '\0'; >+ vp->lvalue = 0; >+ } >+ else /* There is a realm string. */ >+ { >+ if (find_auth_type (u_realm, PW_PROTTYPE_DFLT, >+ (char *) authreq->file_pfx, &type, >+ &agent, &realm, &filter) != 0) >+ { >+ strcpy (vp->strvalue, u_realm); >+ } >+ else /* Use primary (canonical) realm name. */ >+ { >+ strcpy (vp->strvalue, realm); >+ } >+ vp->lvalue = strlen (vp->strvalue); /* Set length */ >+ } >+ >+ /* >+ * Now stick it at end of original request items on the >+ * cur_request list so it can be included in cur_count. >+ */ >+ count = authreq->cur_count; >+ vp_prev = &authreq->cur_request; >+ while (count-- > 0) >+ { >+ if ((vp_prev = &(*vp_prev)->next) == (VALUE_PAIR **) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: cur_count is bad!", func); >+ abort (); >+ } >+ } >+ vp->next = *vp_prev; >+ *vp_prev = vp; >+ >+ authreq->cur_count++; /* indicate and record the additional a/v pair */ >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: name = '%s', realm = '%s'", >+ func, userid, vp->strvalue)); >+ >+ return vp; >+} /* end of parse_realm () */ >+ >+/************************************************************************* >+ * >+ * Function: prune_pairs XXX: turn this into an AATV later >+ * >+ * Purpose: Remove all extraneous a/v pairs before replying to NAS. >+ * >+ * Returns: 0 == normal return, >+ * -1 == some error occurred. >+ * >+ * Remark: This code may change the order of the a/v pairs returned. >+ * >+ *************************************************************************/ >+ >+int >+prune_pairs (authreq, vendor, result) >+ >+AUTH_REQ *authreq; /* modify this request's cur_request list */ >+PRUN_LIST *vendor; /* for this vendor's NAS */ >+int result; /* the packet type Access-Accept or -Reject */ >+ >+{ >+ int i; >+ int j; >+ int msg_flag; >+ int success; >+ VALUE_PAIR **prev_ptr; >+ VALUE_PAIR *vp; >+ short cnt[256]; /* holds the count of each attribute */ >+ static char *func = "prune_pairs"; >+ >+ switch (result) >+ { >+ case EV_ACK: >+ msg_flag = PRUN_FLG1; >+ break; >+ >+ case EV_NAK: >+ msg_flag = PRUN_FLG2; >+ break; >+ >+ case EV_ACC_CHAL: /* Not handled according to RADIUS DRAFT RFC */ >+ return 0; >+ break; >+ >+ default: >+ return (-1); >+ break; >+ } >+ >+ if (result == EV_ACK && authreq->code == PW_ACCOUNTING_REQUEST) /* no */ >+ { >+ list_free (authreq->cur_request); >+ authreq->cur_request = (VALUE_PAIR *) NULL; >+ return 0; >+ } >+ >+ /* Initialize the array cnt[]. */ >+ >+ memset (cnt, '\0', sizeof (cnt)); >+ >+ /* Record the frequency of each reply a/v pair. */ >+ >+ prev_ptr = &authreq->cur_request; >+ for ( vp = *prev_ptr; >+ vp != (VALUE_PAIR *) NULL ; >+ vp = *prev_ptr) >+ { >+ if (vp->attribute > 255) /* then it must be a check-item */ >+ { >+ *prev_ptr = vp->next; >+ free (vp); /* this one is not allowed */ >+ } >+ else /* it is a reply-item, so count it */ >+ { >+ ++cnt[vp->attribute]; >+ prev_ptr = &vp->next; >+ } >+ } >+ >+ /* Prune the cur_request list. */ >+ >+ prev_ptr = &authreq->cur_request; >+ for (vp = *prev_ptr; >+ vp != (VALUE_PAIR *) NULL; >+ vp = *prev_ptr) >+ { >+ j = 0; >+ success = 0; >+ while (vendor->rules[j].value > 0) /* last element is == zero */ >+ { >+ if (vendor->rules[j].value == vp->attribute) >+ { >+ success = 1; >+ break; >+ } >+ j++; >+ } >+ >+ if (success) /* then j is the index into the rules array */ >+ { >+ /* See if this attribute type is allowed in this msg? */ >+ if (vendor->rules[j].flags & msg_flag) >+ { >+ i = vendor->rules[j].count; >+ if (i < 0) >+ { >+ i = 9999; /* pick a suitable infinity */ >+ } >+ >+ if (cnt[vp->attribute] > i) /* reduce counter */ >+ { >+ if (cnt[vp->attribute] > 0) /* if pos */ >+ { >+ --cnt[vp->attribute]; >+ } >+ *prev_ptr = vp->next; >+ free (vp); /* this one is not allowed */ >+ vp = (VALUE_PAIR *) NULL; >+ } >+ else /* it's a keeper! */ >+ { >+ prev_ptr = &vp->next; >+ } >+ } >+ else /* no, unconditionally remove this a/v pair */ >+ { >+ *prev_ptr = vp->next; >+ free (vp); /* this one is not allowed */ >+ vp = (VALUE_PAIR *) NULL; >+ } >+ } >+ else /* this a/v pair is not in the rules, logit and leave it */ >+ { >+ logit (LOG_AUTH, LOG_ERR, >+ "%s: odd attribute number %d in reply", >+ func, vp->attribute); >+ prev_ptr = &vp->next; >+ } >+ } >+ >+ return 0; >+} /* end of prune_pairs () */ >+ >+/************************************************************************* >+ * >+ * Function: _reply_message >+ * >+ * Purpose: Generate a reply message and stick it into the list >+ * of reply items to send back to the client. >+ * >+ * Returns: 0 == normal return >+ * -1 == msgno is out of range >+ * >+ * Remarks: The message is also logged. >+ * >+ *************************************************************************/ >+ >+int >+_reply_message (authreq, msgno, func, filename, line) >+ >+AUTH_REQ *authreq; /* this authentication request */ >+ERRORCODE msgno; /* message number */ >+char *func; /* calling function name */ >+char *filename; /* Filename were error occured. */ >+int line; /* Line number where error occured. */ >+ >+{ >+ static char *msg[] = >+ { >+ "Internal error", >+ "Configuration error", >+ "Out of memory", >+ "Error creating file", >+ "No token available", >+ "No ports available for guests", >+ "Too many simultaneous sessions", >+ "ABS failure", >+ "Error querying balance", >+ "Your account balance is too low" >+ }; >+ >+ if ((u_int)(--msgno) < numbof(msg)) >+ { >+ logit (LOG_AUTH, LOG_INFO, "%s: %s at %s line %d", func, >+ msg[msgno], filename, line); >+ reply_sprintf (0, authreq, "%s [%s()]", msg[msgno], func); >+ return 0; >+ } >+ reply_sprintf (0, authreq, "Software error [%s()]", func); >+ logit (LOG_AUTH, LOG_ERR, "%s: message %d out of range at %s line %d", >+ func, msgno, filename, line); >+ return (-1); >+} /* end of _reply_message () */ >+ >+/************************************************************************* >+ * >+ * Function: reply_sprintf >+ * >+ * Purpose: Generate a reply message and stick it into the list >+ * of reply items to send back to the client. >+ * >+ * Returns: 0 == normal return >+ * -1 == authreq is bad somehow. >+ * >+ * Remarks: The message is also logged if logsw is 1. >+ * It ALWAYS adds a <CR><LF> ("\r\n") to the message. >+ * >+ *************************************************************************/ >+ >+int >+reply_sprintf ( va_alist /* int logsw, AUTH_REQ *authreq, char *format, ... */) >+ >+va_dcl >+ >+{ >+ va_list pvar; >+ >+ int logsw; /* First argument. */ >+ AUTH_REQ *authreq; >+ VALUE_PAIR *msg; >+ char *format; >+ >+ char buf[MAXPATHLEN]; >+ >+ /* Gather parameters. */ >+ >+ va_start (pvar); >+ logsw = va_arg (pvar, int); >+ authreq = va_arg (pvar, AUTH_REQ *); >+ format = va_arg (pvar, char *); >+ >+ /* Format message, add it to reply, log it if necessary. */ >+ >+ vsprintf (buf, format, pvar); >+ >+ if ( logsw != 0 ) >+ { >+ logit (LOG_AUTH, LOG_INFO, "%s", buf); >+ } >+ >+ strcat (buf, "\r\n"); /* Force newline. */ >+ if ((msg = get_last_vp (authreq->cur_request, PW_REPLY_MESSAGE)) >+ != (VALUE_PAIR *) NULL) >+ { >+ /* Check to see if there's any space remaining. */ >+ if ((strlen (buf) + strlen (msg->strvalue)) > AUTH_STRING_LEN) >+ { >+ msg = (VALUE_PAIR *) NULL; >+ } >+ } >+ >+ /* Concatenate the new message onto the last message. */ >+ if (msg != (VALUE_PAIR *) NULL) >+ { >+ strcat (msg->strvalue, buf); >+ } >+ else >+ { >+ avpair_add (&authreq->cur_request, PW_REPLY_MESSAGE, buf, 0); >+ } >+ >+ return 0; >+} /* end of reply_sprintf () */ >+ >+/************************************************************************* >+ * >+ * Function: setupsock >+ * >+ * Purpose: Gets and binds a socket. >+ * >+ *************************************************************************/ >+ >+int >+setupsock (sin, portnum) >+ >+struct sockaddr_in *sin; >+int portnum; >+ >+{ >+ int sock; >+ int sinlen; >+ static char *func = "setupsock"; >+ >+ /* >+ * Get a socket. >+ */ >+ if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) >+ { >+ fprintf (stderr, "%s: socket() UDP socket %d failed, %s\n", >+ func, portnum, sys_errlist[errno]); >+ exit (-11); >+ } >+ sinlen = sizeof (struct sockaddr_in); >+ memset ((char *) sin, '\0', sinlen); >+ >+ /* >+ * Get server's listening port number >+ */ >+ sin->sin_port = htons(portnum); >+ >+ /* >+ * Bind socket to port. bind finds free port if portnum == 0 >+ */ >+ sin->sin_family = AF_INET; >+ sin->sin_addr.s_addr = INADDR_ANY; >+ if (bind (sock, (struct sockaddr *) sin, >+ sizeof (struct sockaddr_in)) < 0) >+ { >+ fprintf (stderr, "%s: bind() UDP socket %d failed, %s\n", >+ func, portnum, sys_errlist[errno]); >+ exit (-11); >+ } >+ /* Retrieve complete socket info */ >+ if (getsockname (sock, (struct sockaddr *) sin, &sinlen) < 0) >+ { >+ fprintf (stderr, "%s: getsockname() UDP socket %d failed, %s\n", >+ func, portnum, sys_errlist[errno]); >+ exit (-11); >+ } >+ return sock; >+} /* end of setupsock () */ >+ >+/************************************************************************* >+ * >+ * Function: trunc_logfile >+ * >+ * Purpose: Truncate, compress and rename the logfile near midnight. >+ * >+ *************************************************************************/ >+ >+void >+trunc_logfile (fd, fname) >+ >+FILE **fd; >+char *fname; >+ >+{ >+ static int archived = 0; >+ struct tm *clock; >+ time_t now; >+ >+ now = time (0); >+ clock = localtime (&now); >+ if (((clock->tm_wday == TRUNCATION_DAY) || (TRUNCATION_DAY == 7)) && >+ (clock->tm_hour == 0 && archived == 0)) >+ { >+ compress_file (fd, fname); >+ >+ archived = 1; >+ } >+ else >+ { >+ if (clock->tm_hour != 0) >+ { >+ archived = 0; >+ } >+ } >+ >+ return; >+} /* end of trunc_logfile () */ >+ >+/************************************************************************* >+ * >+ * Function: type_string >+ * >+ * Purpose: Returns protocol type string for logging of authentication >+ * requests. >+ * >+ *************************************************************************/ >+ >+char * >+type_string (authreq, protpair) >+ >+AUTH_REQ *authreq; >+VALUE_PAIR *protpair; >+ >+{ >+ char *ptr; >+ VALUE_PAIR *user_type; >+ static char string[10]; >+ >+ user_type = get_vp (authreq->request, PW_SERVICE_TYPE); >+ if (user_type != (VALUE_PAIR *) NULL && >+ user_type->lvalue == PW_AUTHENTICATE_ONLY) >+ { >+ ptr = "auth"; >+ } >+ else >+ { >+ ptr = (protpair == (VALUE_PAIR *) NULL) >+ ? "dumb" : avpair_vtoa (protpair, AVPAIR_VTOA_NULL); >+ } >+ strncpy (string, ptr, sizeof (string)); >+ return (string); >+} /* end of type_string () */ >diff -rPu pppd.old/rad_md5.c pppd/rad_md5.c >--- pppd.old/rad_md5.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_md5.c Tue Jul 18 23:01:32 1995 >@@ -0,0 +1,370 @@ >+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm >+ */ >+ >+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All >+rights reserved. >+ >+License to copy and use this software is granted provided that it >+is identified as the "RSA Data Security, Inc. MD5 Message-Digest >+Algorithm" in all material mentioning or referencing this software >+or this function. >+ >+License is also granted to make and use derivative works provided >+that such works are identified as "derived from the RSA Data >+Security, Inc. MD5 Message-Digest Algorithm" in all material >+mentioning or referencing the derived work. >+ >+RSA Data Security, Inc. makes no representations concerning either >+the merchantability of this software or the suitability of this >+software for any particular purpose. It is provided "as is" >+without express or implied warranty of any kind. >+ >+These notices must be retained in any copies of any part of this >+documentation and/or software. >+ */ >+ >+#include "md5.h" >+ >+/* Constants for MD5Transform routine. >+ */ >+#define S11 7 >+#define S12 12 >+#define S13 17 >+#define S14 22 >+#define S21 5 >+#define S22 9 >+#define S23 14 >+#define S24 20 >+#define S31 4 >+#define S32 11 >+#define S33 16 >+#define S34 23 >+#define S41 6 >+#define S42 10 >+#define S43 15 >+#define S44 21 >+ >+static void MD5Transform PROTO_LIST ((UINT4[4], unsigned char[64])); >+static void Encode PROTO_LIST >+ ((unsigned char *, UINT4 *, unsigned int)); >+static void Decode PROTO_LIST >+ ((UINT4 *, unsigned char *, unsigned int)); >+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); >+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); >+ >+static unsigned char PADDING[64] = { >+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >+}; >+ >+/* F, G, H and I are basic MD5 functions. >+ */ >+#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) >+#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) >+#define H(x, y, z) ((x) ^ (y) ^ (z)) >+#define I(x, y, z) ((y) ^ ((x) | (~z))) >+ >+/* ROTATE_LEFT rotates x left n bits. >+ */ >+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) >+ >+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. >+Rotation is separate from addition to prevent recomputation. >+ */ >+#define FF(a, b, c, d, x, s, ac) { \ >+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ >+ (a) = ROTATE_LEFT ((a), (s)); \ >+ (a) += (b); \ >+ } >+#define GG(a, b, c, d, x, s, ac) { \ >+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ >+ (a) = ROTATE_LEFT ((a), (s)); \ >+ (a) += (b); \ >+ } >+#define HH(a, b, c, d, x, s, ac) { \ >+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ >+ (a) = ROTATE_LEFT ((a), (s)); \ >+ (a) += (b); \ >+ } >+#define II(a, b, c, d, x, s, ac) { \ >+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ >+ (a) = ROTATE_LEFT ((a), (s)); \ >+ (a) += (b); \ >+ } >+ >+md5_calc (output, input, inlen) >+unsigned char *output; >+unsigned char *input; /* input block */ >+unsigned int inlen; /* length of input block */ >+{ >+ MD5_CTX context; >+ >+ MD5Init (&context); >+ MD5Update (&context, input, inlen); >+ MD5Final (output, &context); >+} >+ >+/* MD5 initialization. Begins an MD5 operation, writing a new context. >+ */ >+void >+MD5Init (context) >+MD5_CTX *context; /* context */ >+{ >+ context->count[0] = context->count[1] = 0; >+ >+ /* >+ * Load magic initialization constants. >+ */ >+ context->state[0] = 0x67452301; >+ context->state[1] = 0xefcdab89; >+ context->state[2] = 0x98badcfe; >+ context->state[3] = 0x10325476; >+} >+ >+/* MD5 block update operation. Continues an MD5 message-digest >+ operation, processing another message block, and updating the >+ context. >+ */ >+void >+MD5Update (context, input, inputLen) >+MD5_CTX *context; /* context */ >+unsigned char *input; /* input block */ >+unsigned int inputLen; /* length of input block */ >+{ >+ unsigned int i, >+ index, >+ partLen; >+ >+ /* Compute number of bytes mod 64 */ >+ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); >+ >+ /* Update number of bits */ >+ if ((context->count[0] += ((UINT4) inputLen << 3)) >+ < ((UINT4) inputLen << 3)) >+ context->count[1]++; >+ context->count[1] += ((UINT4) inputLen >> 29); >+ >+ partLen = 64 - index; >+ >+ /* >+ * Transform as many times as possible. >+ */ >+ if (inputLen >= partLen) >+ { >+ MD5_memcpy >+ ((POINTER) & context->buffer[index], (POINTER) input, partLen); >+ MD5Transform (context->state, context->buffer); >+ >+ for (i = partLen; i + 63 < inputLen; i += 64) >+ MD5Transform (context->state, &input[i]); >+ >+ index = 0; >+ } >+ else >+ i = 0; >+ >+ /* Buffer remaining input */ >+ MD5_memcpy >+ ((POINTER) & context->buffer[index], (POINTER) & input[i], >+ inputLen - i); >+} >+ >+/* MD5 finalization. Ends an MD5 message-digest operation, writing the >+ the message digest and zeroizing the context. >+ */ >+void >+MD5Final (digest, context) >+unsigned char digest[16]; /* message digest */ >+MD5_CTX *context; /* context */ >+{ >+ unsigned char bits[8]; >+ unsigned int index, >+ padLen; >+ >+ /* Save number of bits */ >+ Encode (bits, context->count, 8); >+ >+ /* >+ * Pad out to 56 mod 64. >+ */ >+ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); >+ padLen = (index < 56) ? (56 - index) : (120 - index); >+ MD5Update (context, PADDING, padLen); >+ >+ /* Append length (before padding) */ >+ MD5Update (context, bits, 8); >+ >+ /* Store state in digest */ >+ Encode (digest, context->state, 16); >+ >+ /* >+ * Zeroize sensitive information. >+ */ >+ MD5_memset ((POINTER) context, 0, sizeof (*context)); >+} >+ >+/* MD5 basic transformation. Transforms state based on block. >+ */ >+static void >+MD5Transform (state, block) >+UINT4 state[4]; >+unsigned char block[64]; >+{ >+ UINT4 a = state[0], >+ b = state[1], >+ c = state[2], >+ d = state[3], >+ x[16]; >+ >+ Decode (x, block, 64); >+ >+ /* Round 1 */ >+ FF (a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ >+ FF (d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ >+ FF (c, d, a, b, x[2], S13, 0x242070db); /* 3 */ >+ FF (b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ >+ FF (a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ >+ FF (d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ >+ FF (c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ >+ FF (b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ >+ FF (a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ >+ FF (d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ >+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ >+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ >+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ >+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ >+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ >+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ >+ >+ /* Round 2 */ >+ GG (a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ >+ GG (d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ >+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ >+ GG (b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ >+ GG (a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ >+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ >+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ >+ GG (b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ >+ GG (a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ >+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ >+ GG (c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ >+ GG (b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ >+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ >+ GG (d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ >+ GG (c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ >+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ >+ >+ /* Round 3 */ >+ HH (a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ >+ HH (d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ >+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ >+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ >+ HH (a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ >+ HH (d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ >+ HH (c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ >+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ >+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ >+ HH (d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ >+ HH (c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ >+ HH (b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ >+ HH (a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ >+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ >+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ >+ HH (b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ >+ >+ /* Round 4 */ >+ II (a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ >+ II (d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ >+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ >+ II (b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ >+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ >+ II (d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ >+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ >+ II (b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ >+ II (a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ >+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ >+ II (c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ >+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ >+ II (a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ >+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ >+ II (c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ >+ II (b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ >+ >+ state[0] += a; >+ state[1] += b; >+ state[2] += c; >+ state[3] += d; >+ >+ /* >+ * Zeroize sensitive information. >+ */ >+ MD5_memset ((POINTER) x, 0, sizeof (x)); >+} >+ >+/* Encodes input (UINT4) into output (unsigned char). Assumes len is >+ a multiple of 4. >+ */ >+static void >+Encode (output, input, len) >+unsigned char *output; >+UINT4 *input; >+unsigned int len; >+{ >+ unsigned int i, >+ j; >+ >+ for (i = 0, j = 0; j < len; i++, j += 4) >+ { >+ output[j] = (unsigned char) (input[i] & 0xff); >+ output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); >+ output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); >+ output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); >+ } >+} >+ >+/* Decodes input (unsigned char) into output (UINT4). Assumes len is >+ a multiple of 4. >+ */ >+static void >+Decode (output, input, len) >+UINT4 *output; >+unsigned char *input; >+unsigned int len; >+{ >+ unsigned int i, >+ j; >+ >+ for (i = 0, j = 0; j < len; i++, j += 4) >+ output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | >+ (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24); >+} >+ >+/* Note: Replace "for loop" with standard memcpy if possible. >+ */ >+ >+static void >+MD5_memcpy (output, input, len) >+POINTER output; >+POINTER input; >+unsigned int len; >+{ >+ unsigned int i; >+ >+ for (i = 0; i < len; i++) >+ output[i] = input[i]; >+} >+ >+/* Note: Replace "for loop" with standard memset if possible. >+ */ >+static void >+MD5_memset (output, value, len) >+POINTER output; >+int value; >+unsigned int len; >+{ >+ unsigned int i; >+ >+ for (i = 0; i < len; i++) >+ ((char *) output)[i] = (char) value; >+} >diff -rPu pppd.old/rad_regexp.c pppd/rad_regexp.c >--- pppd.old/rad_regexp.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_regexp.c Mon Nov 24 19:51:03 1997 >@@ -0,0 +1,24 @@ >+#include <string.h> >+#include <sys/types.h> >+#include <regexp.h> >+ >+int regimatch(const char *expr, const char *str) { >+ regexp *exp; >+ int res; >+ >+ exp = regcomp(expr); >+ res = regexec(exp, str); >+ free(exp); >+ return res; >+} >+ >+#if 0 >+int main(ac, av) >+char *av[]; >+{ >+ char *s1, *s2; >+ if (ac != 3) return 3; >+ s1 = strdup(av[1]); s2 = strdup(av[2]); >+ return regimatch(s1, s2); >+} >+#endif >diff -rPu pppd.old/rad_sendserver.c pppd/rad_sendserver.c >--- pppd.old/rad_sendserver.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_sendserver.c Wed Dec 8 11:11:08 1999 >@@ -0,0 +1,866 @@ >+/* >+ * >+ * RADIUS Remote Authentication Dial In User Service >+ * >+ * >+ * COPYRIGHT (c) 1992, 1993, 1994, 1995, 1996 >+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INCORPORATED >+ * ALL RIGHTS RESERVED >+ * >+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE >+ * THIS SOFTWARE AND SUCH DERIVATIVE WORKS IN BINARY FORM ONLY FOR ANY PURPOSE, >+ * SO LONG AS NO FEE IS CHARGED, AND SO LONG AS THE COPYRIGHT NOTICE ABOVE, THIS >+ * GRANT OF PERMISSION, AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND >+ * SO LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY >+ * ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR DISTRIBUTION OF THIS >+ * SOFTWARE WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. >+ * >+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY >+ * OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE >+ * UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING >+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE >+ * LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR >+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN >+ * CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER >+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. >+ * >+ * For a License to distribute source code or to charge a fee for the program >+ * or a product containing the program, contact MERIT at the University of >+ * Michigan: >+ * >+ * aaa-license@merit.edu >+ * >+ * [This version puts NO LIMITS on the use. It grants the right to create >+ * DERIVATIVE WORKS. The user may copy and distribute the code in the form >+ * received AND DERIVATIVE WORKS, so long as no fee is charged. If copies are >+ * made, our copyright notice and the disclaimer must be included on them. USE >+ * THIS VERSION WITH CARE. THIS VERSION VERY LIKELY WILL KILL ANY POTENTIAL >+ * FOR LATER COMMERCIALIZATION OF THE SOFTWARE.] >+ * >+ * >+ * Public entry points in this file: >+ * >+ * check_radius_reply (only public for the MINOS/MNET daemon) >+ * dir_init >+ * send_server >+ * random_vector >+ * >+ */ >+ >+static char rcsid[] = "$Id: sendserver.c,v 1.54 1996/05/22 19:58:19 web Exp $"; >+ >+#include <sys/types.h> >+#include <sys/socket.h> >+#include <netinet/in.h> >+#include <arpa/inet.h> >+#include <sys/param.h> >+#include <sys/time.h> >+ >+#if !(defined(FD_SET) || defined(linux)) >+#include <sys/select.h> >+#endif /* FD_SET */ >+ >+#include <errno.h> >+#include <netdb.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <syslog.h> >+#include <time.h> >+#include <unistd.h> >+ >+#include "radius.h" >+ >+#if !defined(__FreeBSD__) && !defined(_BSDI_VERSION) && !defined(__NetBSD__) >+extern char *sys_errlist[]; >+#endif /* __FreeBSD__ */ >+ >+#ifndef DEFAULT_SERVER >+#define DEFAULT_SERVER "ns.link-ul.ru" >+#endif >+ >+#ifndef DEFAULT_DIR >+#define DEFAULT_DIR "/var/adm/raddb" >+#endif >+ >+#ifndef DEFAULT_DIR2 >+#define DEFAULT_DIR2 "/var/adm/raddb" >+#endif >+ >+extern char ourhostname[MAXHOSTNAMELEN]; >+extern char *progname; >+extern int debug_flag; >+extern char *radius_dir; >+ >+int radsock = 0; /* fd for radius socket, if non-blocking mode */ >+static int find_server PROTO ((char *, int, UINT4 *, char *, char *)); >+void random_vector PROTO ((u_char *)); >+int check_radius_reply PROTO ((u_char *, char *, u_char *, u_int, char *)); >+ >+/************************************************************************* >+* >+* dir_init - if not set, initializes global var for RADIUS clients >+* >+**************************************************************************/ >+ >+void >+dir_init () >+ >+{ >+ if (radius_dir == NULL || radius_dir[0] == '\0') >+ { >+ radius_dir = DEFAULT_DIR; >+ if (access (radius_dir, X_OK) != 0) >+ { >+ radius_dir = DEFAULT_DIR2; >+ } >+ } >+ return; >+} /* end of dir_init () */ >+ >+/************************************************************************* >+ * >+ * Function: pack_list >+ * >+ * Purpose: Packs an attribute value pair list into a buffer. >+ * >+ * Returns: Number of octets packed. >+ * >+ *************************************************************************/ >+ >+static int >+pack_list (vp, buf) >+ >+VALUE_PAIR *vp; >+char *buf; >+ >+{ >+ int length; >+ int total_length = 0; >+ UINT4 lvalue; >+ >+ while (vp != (VALUE_PAIR *) NULL) >+ { >+ debug_pair (stderr, vp); >+ *buf++ = vp->attribute; >+ >+ switch (vp->type) >+ { >+ case PW_TYPE_STRING: >+ /* length = length = (vp->lvalue > 0) ? >+ vp->lvalue : strlen (vp->strvalue); */ >+ length = strlen (vp->strvalue); >+ *buf++ = length + 2; >+ memcpy (buf, vp->strvalue, length); >+ buf += length; >+ total_length += length + 2; >+ break; >+ >+ case PW_TYPE_INTEGER: >+ case PW_TYPE_IPADDR: >+ *buf++ = sizeof (UINT4) + 2; >+ lvalue = htonl (vp->lvalue); >+ memcpy (buf, (char *) &lvalue, sizeof (UINT4)); >+ buf += sizeof (UINT4); >+ total_length += sizeof (UINT4) + 2; >+ break; >+ >+ default: >+ break; >+ } >+ >+ vp = vp->next; >+ } >+ return total_length; >+} /* end of pack_list () */ >+ >+/************************************************************************* >+* >+* send_server - Sends request to specified RADIUS server and waits >+* for response. Request is retransmitted every >+* "response_timeout" seconds a maximum of "retry_max" >+* times. Result is 0 if response was received, -1 if >+* a problem occurred, or +1 on no-response condition. >+* Returns request retransmit count in "retries" if >+* server does respond. >+* >+* Returns: -1 ERROR_RC -- on local error, >+* 0 OK_RC -- on valid response from server, >+* 1 TIMEOUT_RC -- after retries * resp_timeout seconds, >+* -2 BADRESP_RC -- if response from server had errors. >+* >+**************************************************************************/ >+ >+int >+send_server (data, retries, msg) >+ >+SEND_DATA *data; /* Data structure built by clients */ >+int *retries; /* Maximum num of times to retransmit request */ >+ /* Receives number of retries required, also */ >+char *msg; /* Receives error or advisory message */ >+ >+{ >+ u_char seq_nbr; /* Sequence number to use in request */ >+ int fptype; /* Framed proto, ustype == PW_FRAMED */ >+ int i; >+ int length; >+ int result; >+ int retry_max; >+ int salen; >+ int secretlen; >+ int sockfd; >+ int timeout; /* Number of secs. to wait for response */ >+ int total_length; >+ int ustype; /* User service type for this user */ >+ UINT4 auth_ipaddr; >+ UINT4 lvalue; >+ UINT4 myipaddr; >+ UINT4 port_num; /* Port number to use in request */ >+ AUTH_HDR *auth; >+ VALUE_PAIR *check; >+ char *passwd; /* User password (unencrypted) */ >+ u_char *ptr; >+ VALUE_PAIR *reply; >+ char *server_name; /* Name of server to query */ >+ struct sockaddr_in *sin; >+ struct servent *svp; >+ struct timeval authtime; >+ fd_set readfds; >+ struct sockaddr salocal; >+ struct sockaddr saremote; >+ u_char md5buf[256]; >+ u_char passbuf[AUTH_PASS_LEN]; >+ u_char send_buffer[1024]; >+ u_char recv_buffer[1024]; >+ u_char vector[AUTH_VECTOR_LEN]; >+ char file[MAXPATHLEN]; >+ char secret[MAX_SECRET_LENGTH + 1]; >+ >+#ifdef KCHAP >+ char kchap_auth; >+ u_char buffer[AUTH_PASS_LEN + AUTH_VECTOR_LEN + 1]; >+ u_char digest[AUTH_VECTOR_LEN]; >+ u_char user_secret[CHAP_VALUE_LENGTH + 1]; >+ >+#endif /* KCHAP */ >+ >+ /* Set up some defaults */ >+ dir_init (); >+ >+ server_name = data->server; >+ if (server_name == (char *) NULL || server_name[0] == '\0') >+ { >+ server_name = DEFAULT_SERVER; >+ } >+ >+ ustype = data->ustype; >+ >+#ifdef KCHAP >+ if (ustype == 255) /* KCHAP indicator */ >+ { >+ kchap_auth = 1; >+ ustype = PW_AUTHENTICATE_ONLY; >+ } >+ else >+ { >+ kchap_auth = 0; >+ } >+#endif /* KCHAP */ >+ >+ if (find_server (server_name, ustype, &auth_ipaddr, secret, msg) != 0) >+ { >+ return (ERROR_RC); >+ } >+ >+ timeout = data->timeout; >+ if (timeout == 0) >+ { >+ timeout++; >+ } >+ >+ if (data->svc_port == 0) >+ { >+ if ((svp = getservbyname ("radius", "udp")) == NULL) >+ { >+ data->svc_port = PW_AUTH_UDP_PORT; >+ } >+ else >+ { >+ data->svc_port = ntohs (svp->s_port); >+ } >+ } >+ >+ if (!radsock) >+ { >+ sockfd = socket (AF_INET, SOCK_DGRAM, 0); >+ if (sockfd < 0) >+ { >+ memset (secret, '\0', sizeof (secret)); >+ sprintf (msg, "socket: %s\n", sys_errlist[errno]); >+ return (ERROR_RC); >+ } >+ >+ length = sizeof (salocal); >+ sin = (struct sockaddr_in *) & salocal; >+ memset ((char *) sin, '\0', length); >+ sin->sin_family = AF_INET; >+ sin->sin_addr.s_addr = INADDR_ANY; >+ sin->sin_port = htons (0); >+ if (bind (sockfd, (struct sockaddr *) sin, length) < 0 || >+ getsockname (sockfd, (struct sockaddr *) sin, >+ &length) < 0) >+ { >+ close (sockfd); >+ memset (secret, '\0', sizeof (secret)); >+ sprintf (msg, "bind: %s\n", sys_errlist[errno]); >+ return (ERROR_RC); >+ } >+ retry_max = *retries; /* Max. numbers to try for reply */ >+ *retries = 0; /* Init retry cnt for blocking call */ >+ } >+ else >+ { >+ sockfd = radsock; >+ retry_max = 0; /* No retries if non-blocking */ >+ } >+ >+ /* Build an authentication request */ >+ auth = (AUTH_HDR *) send_buffer; >+ auth->code = data->code; >+ random_vector (vector); >+ seq_nbr = data->seq_nbr; >+ auth->id = seq_nbr; >+ memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); >+ total_length = AUTH_HDR_LEN; >+ ptr = auth->data; >+ >+ /* User Name */ >+ *ptr++ = PW_USER_NAME; >+ length = strlen (data->user_name); >+ if (length > AUTH_ID_LEN) >+ { >+ length = AUTH_ID_LEN; >+ } >+ *ptr++ = length + 2; >+ memcpy ((char *) ptr, data->user_name, length); >+ ptr += length; >+ total_length += length + 2; >+ >+ passwd = data->password; >+ >+ if (auth->code != PW_ACCOUNTING_REQUEST) >+ { >+#ifdef KCHAP >+ if (kchap_auth) >+ { >+ /* User Password */ >+ *ptr++ = PW_CHAP_PASSWORD; >+ *ptr++ = 1 + AUTH_VECTOR_LEN + 2; >+ *ptr++ = seq_nbr; /* Pass CHAP identifier to RADIUS */ >+ *buffer = seq_nbr;/* Put CHAP id in work area for md5 */ >+ afs_pwd_to_secret (passwd, user_secret);/* Get secret */ >+ user_secret[CHAP_VALUE_LENGTH] = '\0'; >+ memcpy ((char *) buffer + 1, (char *) user_secret, >+ CHAP_VALUE_LENGTH); >+ memcpy ((char *) buffer + 1 + CHAP_VALUE_LENGTH, >+ (char *) vector, AUTH_VECTOR_LEN); >+ md5_calc (digest, buffer, >+ 1 + CHAP_VALUE_LENGTH + AUTH_VECTOR_LEN); >+ memcpy ((char *) ptr, (char *) digest, AUTH_VECTOR_LEN); >+ ptr += AUTH_VECTOR_LEN; >+ total_length += 1 + AUTH_VECTOR_LEN + 2; >+ } >+ else >+ { >+#endif /* KCHAP */ >+ >+ /* User Password */ >+ *ptr++ = PW_USER_PASSWORD; >+ *ptr++ = AUTH_PASS_LEN + 2; >+ >+ /* Encrypt the Password */ >+ length = strlen (passwd); >+ if (length > AUTH_PASS_LEN) >+ { >+ length = AUTH_PASS_LEN; >+ } >+ memset ((char *) passbuf, '\0', AUTH_PASS_LEN); >+ memcpy ((char *) passbuf, passwd, length); >+ >+ /* Calculate the MD5 Digest */ >+ secretlen = strlen (secret); >+ strcpy ((char *) md5buf, secret); >+ memcpy ((char *) md5buf + secretlen, >+ (char *) auth->vector, AUTH_VECTOR_LEN); >+ md5_calc (ptr, md5buf, secretlen + AUTH_VECTOR_LEN); >+ >+ /* Xor the password into the MD5 digest */ >+ for (i = 0; i < AUTH_PASS_LEN; i++) >+ { >+ *ptr++ ^= passbuf[i]; >+ } >+ total_length += AUTH_PASS_LEN + 2; >+ >+#ifdef KCHAP >+ } >+#endif /* KCHAP */ >+ } >+ >+ /* Service Type */ >+ *ptr++ = PW_SERVICE_TYPE; >+ *ptr++ = 2 + sizeof (UINT4); >+ lvalue = htonl (ustype); >+ memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4)); >+ ptr = ptr + sizeof (UINT4); >+ total_length += sizeof (UINT4) + 2; >+ >+ fptype = data->fptype; >+ if (fptype > 0) /* if -t [slip | ppp] */ >+ { >+ /* Framed Protocol Type */ >+ *ptr++ = PW_FRAMED_PROTOCOL; >+ *ptr++ = 2 + sizeof (UINT4); >+ lvalue = htonl (fptype); >+ memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4)); >+ ptr = ptr + sizeof (UINT4); >+ total_length += sizeof (UINT4) + 2; >+ } >+ >+ /* Client IP Address */ >+ *ptr++ = PW_NAS_IP_ADDRESS; >+ *ptr++ = 2 + sizeof (UINT4); >+ myipaddr = htonl(data->client_id); >+ memcpy ((char *) ptr, (char *) &myipaddr, sizeof (UINT4)); >+ ptr = ptr + sizeof (UINT4); >+ total_length += sizeof (UINT4) + 2; >+ >+ /* Client Port Number */ >+ *ptr++ = PW_NAS_PORT; >+ *ptr++ = 2 + sizeof (UINT4); >+ port_num = htonl((UINT4) data->port_num); >+ memcpy ((char *) ptr, (char *) &port_num, sizeof (UINT4)); >+ ptr = ptr + sizeof (UINT4); >+ total_length += sizeof (UINT4) + 2; >+ >+ if (data->user_file != (char *) NULL) /* add a/v pairs from user_file */ >+ { >+ sprintf (file, "%s.", data->user_file); >+ check = (VALUE_PAIR *) NULL; >+ if ((user_find (file, data->group, 0, &check, &reply, 1)) == 0) >+ { >+ total_length += (length = pack_list (check, ptr)); >+ ptr += length; >+ total_length += (length = pack_list (reply, ptr)); >+ ptr += length; >+ } >+ } >+ >+ if (data->send_pairs != (VALUE_PAIR *) NULL) /* add more a/v pairs */ >+ { >+ total_length += (length = pack_list (data->send_pairs, ptr)); >+ ptr += length; >+ } >+ >+ auth->length = htons (total_length); >+ >+ sin = (struct sockaddr_in *) & saremote; >+ memset ((char *) sin, '\0', sizeof (saremote)); >+ sin->sin_family = AF_INET; >+ sin->sin_addr.s_addr = htonl (auth_ipaddr); >+ sin->sin_port = htons (data->svc_port); >+ >+ for (;;) >+ { >+ sendto (sockfd, (char *) auth, (int) total_length, (int) 0, >+ (struct sockaddr *) sin, sizeof (struct sockaddr_in)); >+ >+ if (radsock) >+ { /* If non-blocking */ >+ >+ /* >+ * Return stuff to be saved for evaluation of reply >+ * when it comes in >+ */ >+ strcpy (msg, secret); >+ memcpy (msg + strlen (msg) + 1, (char *) vector, >+ AUTH_VECTOR_LEN); >+ memset (secret, '\0', sizeof (secret)); >+ return 1; /* Pos. return means no error */ >+ } >+ authtime.tv_usec = 0L; >+ authtime.tv_sec = (long) timeout; >+ FD_ZERO (&readfds); >+ FD_SET (sockfd, &readfds); >+ if (select (sockfd + 1, &readfds, NULL, NULL, &authtime) < 0) >+ { >+ if (errno == EINTR) >+ continue; >+ sprintf (msg, "select: %s\n", sys_errlist[errno]); >+ memset (secret, '\0', sizeof (secret)); >+ close (sockfd); >+ return (ERROR_RC); >+ } >+ if (FD_ISSET (sockfd, &readfds)) >+ break; >+ >+ /* >+ * Timed out waiting for response. Retry "retry_max" times >+ * before giving up. If retry_max = 0, don't retry at all. >+ */ >+ if (++(*retries) >= retry_max) >+ { >+ if (debug_flag > 0) >+ { >+ fprintf (stderr, "\n"); >+ } >+ sprintf (msg, >+ "No reply from RADIUS server \"%s(%u)\"\n", >+ ip_hostname (auth_ipaddr), data->svc_port); >+ close (sockfd); >+ memset (secret, '\0', sizeof (secret)); >+ return (TIMEOUT_RC); >+ } >+ else >+ { >+ if (debug_flag > 0) >+ { >+ fprintf (stderr, "."); >+ } >+ } >+ } >+ salen = sizeof (saremote); >+ length = recvfrom (sockfd, (char *) recv_buffer, >+ (int) sizeof (recv_buffer), >+ (int) 0, &saremote, &salen); >+ >+ if (length <= 0) >+ { >+ sprintf (msg, "recvfrom: %s\n", sys_errlist[errno]); >+ close (sockfd); >+ memset (secret, '\0', sizeof (secret)); >+ return (ERROR_RC); >+ } >+ result = check_radius_reply (recv_buffer, secret, vector, >+ (u_int) seq_nbr, msg); >+ close (sockfd); >+ memset (secret, '\0', sizeof (secret)); >+ return (result); >+} /* end of send_server () */ >+ >+/************************************************************************* >+* >+* check_radius_reply - Verify items in returned packet. >+* >+* Returns: OK_RC -- upon success, >+* BADRESP_RC -- if anything looks funny. >+* >+* Public entry point necessary for MINOS/MNET daemon. >+* >+**************************************************************************/ >+ >+int >+check_radius_reply (buffer, secret, vector, seq_nbr, msg) >+ >+u_char *buffer; >+char *secret; >+u_char vector[]; >+u_int seq_nbr; >+char *msg; >+ >+{ >+ u_char len; >+ int result; >+ int secretlen; >+ int totallen; >+ AUTH_HDR *auth; >+ u_char *next; >+ u_char *ptr; >+ VALUE_PAIR *vp; >+ u_char calc_digest[AUTH_VECTOR_LEN]; >+ u_char reply_digest[AUTH_VECTOR_LEN]; >+ >+ auth = (AUTH_HDR *) buffer; >+ totallen = ntohs (auth->length); >+ >+ /* Verify that id (seq. number) matches what we sent */ >+ if (auth->id != (u_char) seq_nbr) >+ { >+ sprintf (msg, "Received non-matching id in server response\n"); >+ return (BADRESP_RC); >+ } >+ >+ /* Verify the reply digest */ >+ memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN); >+ memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); >+ secretlen = strlen (secret); >+ memcpy ((char *) buffer + totallen, secret, secretlen); >+ md5_calc (calc_digest, (char *) auth, totallen + secretlen); >+ >+ if (memcmp ((char *) reply_digest, (char *) calc_digest, >+ AUTH_VECTOR_LEN) != 0) >+ { >+ sprintf (msg, "Received invalid reply digest from server\n"); >+ return (BADRESP_RC); >+ } >+ >+ if (debug_flag) >+ { >+ fprintf (stderr, "Received attribute/value pair(s):\n"); >+ vp = gen_valpairs (auth); /* just to print out in debug mode */ >+ } >+ >+ msg[0] = '\0'; >+ ptr = (u_char *) auth->data; >+ totallen -= AUTH_HDR_LEN; >+ while (totallen > 0) >+ { >+ len = ptr[1]; >+ totallen -= len; >+ next = ptr + len; >+ if (*ptr == '\0') >+ { >+ sprintf (msg, "Received bad attribute type from server\n"); >+ return (BADRESP_RC); >+ } >+ >+ if (*ptr == PW_REPLY_MESSAGE) >+ { >+ ptr++; >+ ptr++; >+ strncat (msg, (char *) ptr, len - 2); >+ strcat (msg, "\n"); >+ } >+ ptr = next; >+ } >+ >+ if ((auth->code == PW_ACCESS_ACCEPT) || >+ (auth->code == PW_PASSWORD_ACK) || >+ (auth->code == PW_ACCOUNTING_RESPONSE)) >+ { >+ result = OK_RC; >+ } >+ else >+ { >+ result = BADRESP_RC; >+ } >+ >+ return (result); >+} /* end of check_radius_reply () */ >+ >+/************************************************************************* >+* >+* random_vector - Generates a random vector of AUTH_VECTOR_LEN octets. >+* >+* Returns: the vector (call by reference) >+* >+**************************************************************************/ >+ >+void >+random_vector (vector) >+ >+u_char *vector; >+ >+{ >+ int randno; >+ int i; >+ >+ srand (time (0)); >+ for (i = 0; i < AUTH_VECTOR_LEN;) >+ { >+ randno = rand (); >+ memcpy ((char *) vector, (char *) &randno, sizeof (int)); >+ vector += sizeof (int); >+ i += sizeof (int); >+ } >+ return; >+} /* end of random_vector () */ >+ >+/************************************************************************* >+* >+* find_match - See if given IP address matches any address of hostname. >+* >+* Returns: 0 success >+* -1 failure >+* >+**************************************************************************/ >+ >+static int >+find_match (ip_addr, hostname) >+ >+UINT4 *ip_addr; >+char *hostname; >+ >+{ >+ UINT4 addr; >+ char **paddr; >+ struct hostent *hp; >+ >+ if (good_ipaddr (hostname) == 0) >+ { >+ if (*ip_addr == ntohl(inet_addr (hostname))) >+ { >+ return (0); >+ } >+ } >+ else >+ { >+ if ((hp = gethostbyname (hostname)) == (struct hostent *) NULL) >+ { >+ return (-1); >+ } >+ if (hp->h_addr_list != (char **) NULL) >+ { >+ for (paddr = hp->h_addr_list; *paddr; paddr++) >+ { >+ addr = ** (UINT4 **) paddr; >+ if (ntohl(addr) == *ip_addr) >+ { >+ return (0); >+ } >+ } >+ } >+ } >+ return (-1); >+} /* end of find_match */ >+ >+/************************************************************************* >+* >+* find_server - Look up the given server name in the clients file. >+* >+* Returns: 0 success >+* -1 failure >+* >+**************************************************************************/ >+ >+static int >+find_server (server_name, ustype, ip_addr, secret, msg) >+ >+char *server_name; >+int ustype; >+UINT4 *ip_addr; >+char *secret; >+char *msg; >+ >+{ >+ static UINT4 myipaddr = 0; >+ int len; >+ int line_nbr = 0; >+ int result; >+ FILE *clientfd; >+ char *h; >+ char *s; >+ char *host2; >+ char buffer[128]; >+ char fname[MAXPATHLEN]; >+ char hostnm[AUTH_ID_LEN + 1]; >+ >+ /* Get the IP address of the authentication server */ >+ if ((*ip_addr = get_ipaddr (server_name)) == (UINT4) 0) >+ { >+ sprintf (msg, "No such server: \"%s\"\n", server_name); >+ return (-1); >+ } >+ /* Just use dummy secret for management polls */ >+ if (ustype == PW_ADMINISTRATIVE_USER) /* was old PW_MANAGEMENT_POLL */ >+ { >+ strcpy (secret, MGMT_POLL_SECRET); >+ return 0; >+ } >+ sprintf (fname, "%s/%s", radius_dir, RADIUS_CLIENTS); >+ if ((clientfd = fopen (fname, "r")) == (FILE *) NULL) >+ { >+ sprintf (msg, "Couldn't open file \"%s\"\n", fname); >+ return (-1); >+ } >+ if (!myipaddr) >+ { >+ if ((myipaddr = get_ipaddr (ourhostname)) == 0) >+ { >+ sprintf (msg, "Couldn't get our own ip address\n"); >+ fclose (clientfd); >+ return (-1); >+ } >+ } >+ >+ result = 0; >+ while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL) >+ { >+ line_nbr++; >+ >+ if (*buffer == '#') >+ { >+ continue; >+ } >+ >+ if ((h = strtok (buffer, " \t\n\r")) == NULL) /* 1st hostname */ >+ { >+ continue; >+ } >+ >+ memset (hostnm, '\0', AUTH_ID_LEN); >+ len = strlen (h); >+ if (len > AUTH_ID_LEN) >+ { >+ len = AUTH_ID_LEN; >+ } >+ strncpy (hostnm, h, len); >+ hostnm[AUTH_ID_LEN] = '\0'; >+ >+ if ((s = strtok (NULL, " \t\n\r")) == NULL) /* & secret field */ >+ { >+ continue; >+ } >+ >+ memset (secret, '\0', MAX_SECRET_LENGTH); >+ len = strlen (s); >+ if (len > MAX_SECRET_LENGTH) >+ { >+ len = MAX_SECRET_LENGTH; >+ } >+ strncpy (secret, s, len); >+ secret[MAX_SECRET_LENGTH] = '\0'; >+ >+ if (!strchr (hostnm, '/')) /* If single name form */ >+ { >+ if (find_match (ip_addr, hostnm) == 0) >+ { >+ result++; >+ break; >+ } >+ } >+ else /* <name1>/<name2> "paired" form */ >+ { >+ strtok (hostnm, "/"); /* replaces "/" with NULL char */ >+ host2 = strtok (NULL, " "); >+ if (find_match (&myipaddr, hostnm) == 0) >+ { /* If we're the 1st name, target is 2nd */ >+ if (find_match (ip_addr, host2) == 0) >+ { >+ result++; >+ break; >+ } >+ } >+ else /* Check to see if we are the second name */ >+ { >+ if (find_match (&myipaddr, host2) == 0) >+ { /* We are the 2nd name, target is 1st name */ >+ if (find_match (ip_addr, hostnm) == 0) >+ { >+ result++; >+ break; >+ } >+ } >+ } >+ } >+ } >+ fclose (clientfd); >+ if (result == 0) >+ { >+ memset (buffer, '\0', sizeof (buffer)); >+ memset (secret, '\0', sizeof (secret)); >+ sprintf (msg, "Couldn't find server in \"%s/%s\": \"%s\"\n", >+ radius_dir, RADIUS_CLIENTS, server_name); >+ return (-1); >+ } >+ return 0; >+} /* end of find_server () */ >diff -rPu pppd.old/rad_users.c pppd/rad_users.c >--- pppd.old/rad_users.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_users.c Tue Nov 25 05:24:06 1997 >@@ -0,0 +1,3175 @@ >+ /* >+ * 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. >+ * >+ * [C] The Regents of the University of Michigan and Merit Network, Inc. 1992, >+ * 1993, 1994, 1995, 1996 All Rights Reserved >+ * >+ * 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 and this permission notice appear in all >+ * copies of the software and derivative works or modified versions thereof, >+ * and that both the copyright notice and this permission and disclaimer >+ * notice appear in supporting documentation. >+ * >+ * 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. >+ * >+ * Public entry points in this file: >+ * >+ * add_file_list >+ * config_init >+ * config_files >+ * config_fini >+ * dns_recv >+ * find_auth_type >+ * find_auth_ent >+ * find_client >+ * find_client_by_name >+ * find_host_by_name >+ * free_user_ent >+ * get_our_addr >+ * ip_hostname >+ * list_cat >+ * list_copy >+ * pair_parse >+ * return_file_list >+ * user_find >+ * user_gettime >+ * user_update >+ * >+ */ >+ >+static char sccsid[] = >+ "@(#)users.c 1.3 Copyright 1992 Livingston Enterprises Inc"; >+ >+static char rcsid[] = "$Id: users.c,v 1.89 1996/06/11 21:10:39 web Exp $"; >+ >+#include <sys/types.h> >+#include <sys/param.h> >+#include <sys/socket.h> >+#include <sys/time.h> >+#include <netinet/in.h> >+#include <arpa/inet.h> >+ >+#include <stdio.h> >+#include <stdlib.h> >+#include <netdb.h> >+#include <time.h> >+#include <ctype.h> >+#include <dirent.h> >+#include <syslog.h> >+ >+#include "radius.h" >+ >+static void fieldcpy PROTO((char *, char **)); >+static FILE_LIST *find_file_ent PROTO((char *)); >+static void free_clients PROTO((CLIENT_ENTRY *)); >+static void free_file_lists PROTO((void)); >+static int host_is_us PROTO((char *)); >+static int insert_client PROTO((char *, char *, char *)); >+static int read_auth PROTO((FILE_LIST *, int)); >+static int read_users PROTO((FILE_LIST *, int)); >+ >+#if defined(ultrix) || defined(__hpux) || defined(__bsdi__) || defined(linux) || defined(SCO) >+extern int h_errno; >+#endif /* ultrix */ >+ >+extern char send_buffer[4096]; >+extern char recv_buffer[4096]; >+extern char ourhostname[MAXHOSTNAMELEN]; >+extern AATV *authtype_tv[]; /* AATVs by authentication types */ >+extern int debug_flag; >+extern int dumpcore; >+extern char *radius_dir; >+extern FILE *ddt; >+extern int authfile_cnt; >+extern int clients_cnt; >+extern int users_cnt; >+extern int file_logging; /* 0 => syslog, 1 => logfile, 2 => stderr */ >+extern AATV *rad_ipc_aatv; >+extern FILE *msgfd; >+ >+int spawn_flag = 1; >+int dnspid = 0; /* PID of current DNS resolver process */ >+char default_radius_server[128] = DEFAULT_RADIUS_SERVER; >+char default_tacacs_server[128] = DEFAULT_TACACS_SERVER; >+int rad_ipc_port = 0; >+ >+static FILE_LIST *file_list = (FILE_LIST *) NULL; >+static CLIENT_ENTRY *client_list = (CLIENT_ENTRY *) NULL; >+ >+static UINT4 self_ip[11]; /* Used with multi-homed servers */ >+static int is_engine = 0; /* rlmadmin will not change this */ >+static CLIENT_ENTRY *old_clients; >+ >+/************************************************************************* >+ * >+ * Function: add_file_list >+ * >+ * Purpose: Find an existing FILE_LIST entry on file_list with the >+ * specified prefix or add and init a new one if the >+ * entry doesn't already exist. >+ * >+ *************************************************************************/ >+ >+int >+add_file_list (prefix) >+ >+char *prefix; >+ >+{ >+ FILE_LIST *file_ent; >+ FILE_LIST **fl_prev; >+ static char *func = "add_file_list"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ for (fl_prev = &file_list, file_ent = file_list; >+ file_ent; >+ fl_prev = &file_ent->next, file_ent = *fl_prev) >+ { >+ if (strcmp (file_ent->prefix, prefix) == 0) >+ { >+ return 0; >+ } >+ } >+ >+ if ((file_ent = (FILE_LIST *) malloc (sizeof (FILE_LIST))) >+ == (FILE_LIST *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: Couldn't allocate FILE_ENTRY storage", func); >+ return (-1); >+ } >+ file_ent->prefix = add_string (prefix, ASIS); >+ file_ent->user_list = (USER_ENTRY *) NULL; >+ file_ent->auth_list = (AUTH_ENTRY *) NULL; >+ file_ent->next = (FILE_LIST *) NULL; >+ *fl_prev = file_ent; >+ >+ return 0; >+} /* end of add_file_list () */ >+ >+/************************************************************************* >+ * >+ * Function: config_init >+ * >+ * Purpose: Setup environment for config_files() to run in. >+ * >+ *************************************************************************/ >+ >+void >+config_init () >+ >+{ >+ is_engine = 1; /* flag set when engine calls us */ >+ >+ /* >+ * Set dnspid to defer the call to update_clients() >+ * until the end of config_files(). >+ */ >+ if (dnspid == 0) >+ { >+ dnspid = -1; >+ } >+ >+ /* >+ * Save the old clients list so we can pick up >+ * the DNS addresses for the new list. >+ */ >+ old_clients = client_list; >+ client_list = (CLIENT_ENTRY *) NULL; >+ return; >+} /* end of config_init () */ >+ >+/************************************************************************* >+ * >+ * Function: config_files >+ * >+ * Purpose: Read database files into memory data structures. Reads >+ * "RADIUS_CLIENTS" and "RADIUS_AUTH" files unconditionally >+ * and "RADIUS_USERS" file if users_flag is not zero. Will >+ * read multiple users and authfiles if the "file_pfx" is >+ * specified in a client entry (allowing use of different >+ * files for different client NASes). >+ * >+ * If clear_flag is greater than zero, remove existing entries. >+ * >+ * A new CLIENT_ENTRY is added to the client_list for each >+ * client appearing in the "RADIUS_CLIENTS" file. A new >+ * FILE_LIST entry is added for each unique file_pfx found >+ * in the "RADIUS_CLIENTS" file. Each FILE_LIST entry points >+ * to a list of USER_ENTRYs containing the information read >+ * from the "RADIUS_USERS" file with the corresponding >+ * file_pfx. Also each FILE_LIST entry contains a pointer to >+ * the list of AUTH_ENTRYs containing realm information read >+ * from the "RADIUS_AUTH" file with the corresponding file_pfx. >+ * If either the "RADIUS_USERS" file or the "RADIUS_AUTH" file >+ * with the given file_pfx did not exist, the default >+ * (non-prefixed) file name entries are used instead. >+ * >+ *************************************************************************/ >+ >+int >+config_files (users_flag, clear_flag, dolog) >+ >+int users_flag; >+int clear_flag; >+int dolog; >+ >+{ >+ int i; >+ int ent_cnt = 0; >+ int line_nbr = 0; >+ int result; >+ FILE_LIST *file_ent; >+ FILE *clientfd; >+ struct hostent *hp; >+ char *file_pfx; >+ char *host; >+ char *hostnm; >+ char *secret; >+ char **paddr; >+ char buffer[128]; >+ char fname[MAXPATHLEN]; >+ static char *func = "config_files"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (clear_flag > 0) /* Free current list, if already set up */ >+ { >+ free_file_lists (); >+ } >+ >+ /* >+ * Add default file_list entry - the entry for the "users" and >+ * "authfile" with no optional prefix >+ */ >+ add_file_list (""); >+ >+ /* >+ * Determine the IP address(es) of this machine >+ */ >+ if ((hp = gethostbyname (ourhostname)) == (struct hostent *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_CRIT, >+ "%s: Couldn't get our own IP address(es)", func); >+ return (-1); >+ } >+ >+ /* >+ * First clear, then save our IP address(es) >+ * leaving a zero entry at the end. >+ */ >+ memset ((char *) self_ip, '\0', sizeof (self_ip)); >+ >+ if (hp->h_addr_list != (char **) NULL) >+ { >+ for (i = 0, paddr = hp->h_addr_list; >+ (*paddr != (char *) NULL) && >+ (i < sizeof (self_ip) / 4 - 1); >+ i++, paddr++) >+ { >+ memcpy ((char *) &self_ip[i], (char *) *paddr, >+ hp->h_length); >+ self_ip[i] = ntohl(self_ip[i]); >+ } >+ } >+ >+ /* >+ * Now read in all client file entries, adding a new "CLIENT_ENTRY" >+ * to client_list for each valid file entry found. If there is more >+ * than one IP address for a given client DNS name, add an entry for >+ * each address. >+ */ >+ sprintf (fname, "%s/%s", radius_dir, RADIUS_CLIENTS); >+ if ((clientfd = fopen (fname, "r")) == (FILE *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: Couldn't open %s for reading", >+ func, fname); >+ return (-1); >+ } >+ >+ clients_cnt = 0; >+ result = -1; /* Init result code */ >+ >+ while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL) >+ { >+ line_nbr++; >+ >+ if (*buffer == COMMENT) >+ { >+ continue; >+ } >+ >+ /* first hostname */ >+ if ((hostnm = strtok (buffer, " \t\n\r")) == (char *) NULL) >+ { >+ continue; >+ } >+ >+ /* and secret field */ >+ if ((secret = strtok (NULL, " \t\n\r")) == (char *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: missing shared secret: %s line %d", >+ func, fname, line_nbr); >+ continue; >+ } >+ >+ file_pfx = strtok (NULL, " \t\n\r"); /* optional prefix */ >+ >+ /* >+ * Look for "paired" <name1>/<name2> entries. This type of >+ * entry allows core RADIUS servers to share a common "clients" >+ * file. If we're name1, name2 is the target name; if we are >+ * name2, then name1 is the target. If we're neither name, >+ * then this entry isn't of interest to us and we ignore it. >+ */ >+ host = hostnm; /* Assume just one name */ >+ >+ if (strchr (hostnm, '/')) /* If <name1>/<name2> form */ >+ { >+ strtok (hostnm, "/"); >+ host = strtok (NULL, " "); >+ if (host_is_us (hostnm)) >+ { >+ /* We are 1st name - client is 2nd */ >+ } >+ else >+ { >+ if (host_is_us (host)) >+ { >+ /* We are 2nd - client is 1st */ >+ host = hostnm; >+ } >+ else /* We are neither - no match */ >+ { >+ continue; >+ } >+ } >+ } >+ >+ if ((result = insert_client (host, secret, file_pfx)) < 0) >+ { >+ break; >+ } >+ ent_cnt++; >+ } /* end of while () */ >+ fclose (clientfd); >+ if (dolog) >+ { >+ logit (LOG_DAEMON, LOG_INFO, >+ "%s: %s (%u entries) read to memory", >+ func, fname, ent_cnt); >+ } >+ clients_cnt = ent_cnt; >+ >+ /* >+ * Finally, go through all the file_list entries just added, reading >+ * in the "users" and "authfile" for each prefix found. >+ */ >+ for (file_ent = file_list; file_ent; file_ent = file_ent->next) >+ { >+ >+#if !(defined(USE_DBM) || defined(USE_NDBM)) >+ if (users_flag) >+ if (read_users (file_ent, dolog) != 0) >+ { >+ return (-1); >+ } >+#endif /* USE_DBM || USE_NDBM */ >+ >+ if (read_auth (file_ent, dolog) != 0) >+ { >+ return (-1); >+ } >+ >+ } >+ >+ if (result < 0) >+ { >+ return (-1); >+ } >+ >+ return 0; >+} /* end of config_files () */ >+ >+/************************************************************************* >+ * >+ * Function: config_fini >+ * >+ * Purpose: Cleanup environment after config_files() has run. >+ * >+ *************************************************************************/ >+ >+void >+config_fini () >+ >+{ >+ free_clients (old_clients); >+ old_clients = (CLIENT_ENTRY *) NULL; >+ >+ if ((file_logging == 1) && (msgfd != (FILE *) NULL)) >+ { >+ fflush (msgfd); >+ } >+ >+ if (dnspid == -1) >+ { >+ dnspid = 0; >+ } >+ >+ update_clients (); /* Start up the DNS resolver. */ >+ >+ return; >+} /* end of config_fini () */ >+ >+/************************************************************************* >+ * >+ * Function: dns_recv >+ * >+ * Purpose: Process received DNS updates for clients database. >+ * >+ *************************************************************************/ >+ >+void >+dns_recv (sin, from_ipaddr, rcvlen) >+ >+struct sockaddr_in *sin; >+UINT4 from_ipaddr; >+int rcvlen; >+ >+{ >+ int cnt; >+ u_char aliascnt; >+ UINT4 temp; >+ UINT4 *ourad; >+ char *ptr; >+ IP_ADDRESS *an_address; >+ DNS_NAME *a_name; >+ CLIENT_ENTRY *client_ent; >+ static int notify_count = 0; >+ static char *func = "dns_recv"; >+ >+ notify_count ++; >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered (%d)", >+ func, notify_count)); >+ >+ ptr = recv_buffer + 1; >+ >+ for (ourad = self_ip; >+ (*ourad != (UINT4) 0) && (*ourad != from_ipaddr); >+ ourad++) >+ { >+ continue; >+ } >+ >+ if (*ourad == (UINT4) 0) >+ { >+ logit (LOG_DAEMON, LOG_INFO, "%s: from %s - Security Breach", >+ func, ip_hostname (from_ipaddr)); >+ return; >+ } >+ >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_ent->next) >+ { >+ if (strcmp (ptr, client_ent->hostname) == 0) >+ { >+ break; >+ } >+ } >+ >+ if (client_ent == (CLIENT_ENTRY *) NULL) >+ { >+ return; >+ } >+ >+ ptr += strlen (ptr) + 1; >+ aliascnt = *ptr++; >+ >+ if (*ptr != '\0') /* If alias or IP address present, clear old ones */ >+ { >+ /* >+ * Reset expire_time with some randomness (0 - 60 minutes) >+ * to avoid a burst of calls to gethostbyname(). >+ */ >+ client_ent->expire_time = (time (0) + ADDRESS_AGING + >+ (rand () & 3) * 60 * 20) & ~3; >+ for (an_address = client_ent->addrs; >+ an_address != (IP_ADDRESS *) NULL; >+ an_address = client_ent->addrs) >+ { >+ client_ent->addrs = an_address->next; >+ free (an_address); >+ } >+ >+ for (a_name = client_ent->names; >+ a_name != (DNS_NAME *) NULL; >+ a_name = client_ent->names) >+ { >+ client_ent->names = a_name->next; >+ free (a_name); >+ } >+ } >+ else /* no alias or IP address present */ >+ { >+ memcpy ((char *) &temp, ptr, sizeof (struct in_addr)); >+ if (temp == TRY_AGAIN) /* TRY_AGAIN is in netdb.h */ >+ { >+ client_ent->expire_time = (time (0) + ADDRESS_AGING) >+ & ~3; >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: DNS timeout on client or host '%s'", >+ func, client_ent->hostname); >+ return; >+ } >+ else >+ { >+ /* >+ * Name couldn't be resolved -- log it and retry >+ * shortly. Cleverly (or foolishly) use the low >+ * two bits of expire_time to control the logging >+ * frequency. >+ */ >+ if ((cnt = client_ent->expire_time & 3) == 0) >+ { >+ /* Log every fourth time (or once per hour) */ >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: DNS couldn't resolve name '%s' (%ld)", >+ func, client_ent->hostname, temp); >+ } >+ >+ client_ent->expire_time = ((time (0) + ADDRESS_AGING/4) >+ & ~3) | (++cnt & 3); >+ if (client_ent->addrs != (IP_ADDRESS *) NULL) >+ { >+ return; >+ } >+ >+ /* Add invalid address to client_ent */ >+ memset (ptr, 255, sizeof (struct in_addr)); >+ } >+ } >+ >+ /* Add alias names to client_ent structure */ >+ while (aliascnt-- > 0) >+ { >+ /* Note that DNS_NAME structure reserves one extra character. */ >+ if ((a_name = >+ (DNS_NAME *) malloc (sizeof (DNS_NAME) + strlen (ptr))) >+ == (DNS_NAME *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL Couldn't allocate DNS_NAME storage", >+ func); >+ abort (); >+ } >+ >+ /* Note that type zero will always be last one. */ >+ strcpy (a_name->name, ptr); >+ ptr += strlen (ptr) + 1; >+ a_name->type = (u_char) *ptr++; >+ a_name->next = client_ent->names; >+ client_ent->names = a_name; >+ } >+ >+ /* >+ * For each address in the list, add the address to the client_ent. >+ */ >+ while (*ptr != '\0') >+ { >+ if ((an_address = (IP_ADDRESS *) malloc (sizeof (IP_ADDRESS))) >+ == (IP_ADDRESS *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL Couldn't allocate IP_ADDRESS storage", >+ func); >+ abort (); >+ } >+ >+ an_address->next = client_ent->addrs; >+ memcpy ((char *) &temp, ptr, sizeof (struct in_addr)); >+ an_address->ipaddr.s_addr = ntohl(temp); >+ client_ent->addrs = an_address; >+ ptr += sizeof (struct in_addr); >+ } >+ >+ if (notify_count % DNS_SLEEP == DNS_SLEEP - 1) >+ { >+ logit (LOG_DAEMON, LOG_INFO, "%s: Notified of (%d) DNS changes", >+ func, notify_count); >+ } >+ >+ return; >+} /* end of dns_recv () */ >+ >+/************************************************************************* >+ * >+ * Function: fieldcpy >+ * >+ * Purpose: Copy a data field from the buffer. Advance the buffer >+ * past the data field. >+ * >+ *************************************************************************/ >+ >+static void >+fieldcpy (string, uptr) >+ >+char *string; >+char **uptr; >+ >+{ >+ char *ptr; >+ >+ ptr = *uptr; >+ if (*ptr == '"') >+ { >+ ptr++; >+ while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') >+ { >+ *string++ = *ptr++; >+ } >+ *string = '\0'; >+ if (*ptr == '"') >+ { >+ ptr++; >+ } >+ *uptr = ptr; >+ return; >+ } >+ >+ while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' && >+ *ptr != '=' && *ptr != ',') >+ { >+ *string++ = *ptr++; >+ } >+ *string = '\0'; >+ *uptr = ptr; >+ return; >+} /* end of fieldcpy () */ >+ >+/************************************************************************* >+ * >+ * Function: find_auth_ent >+ * >+ * Purpose: Gives access to the private AUTH_ENT for the given realm. >+ * >+ * Returns: pointer to the AUTH_ENT for the given realm, >+ * or, NULL, if error. >+ * >+ *************************************************************************/ >+ >+AUTH_ENTRY * >+find_auth_ent (u_realm, prot, pfx) >+ >+char *u_realm; >+int prot; >+char *pfx; >+ >+{ >+ int head; >+ int pat_len; >+ FILE_LIST *file_ent; >+ AUTH_ENTRY *auth_ent; >+ AUTH_ENTRY *entry; >+ char *p; >+ char *realm_name; >+ static char temp[AUTH_ID_LEN + 1]; >+ static char *func = "find_auth_ent"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (u_realm[0] == 0) /* A null realm would match every line. */ >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: NULL realm", func)); >+ return (AUTH_ENTRY *) NULL; >+ } >+ >+ if ((file_ent = find_file_ent (pfx)) == (FILE_LIST *) NULL) >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: NULL file_ent", func)); >+ return (AUTH_ENTRY *) NULL; >+ } >+ >+ if ((auth_ent = file_ent->auth_list) == (AUTH_ENTRY *) NULL) >+ { >+ /* If no auth_list for this prefix */ >+ file_ent = file_list; >+ /* Default file_ent is first in file_list */ >+ if ((auth_ent = file_ent->auth_list) == (AUTH_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: no default authfile data structure", >+ func); >+ return (AUTH_ENTRY *) NULL; >+ } >+ } >+ >+ /* >+ * Match realm name (either exact match or substring match >+ * based on *.realm syntax) with user supplied string. >+ */ >+ for ( ; auth_ent ; auth_ent = auth_ent->next ) >+ { >+ realm_name = (char *) NULL; >+ if (auth_ent->parent == (AUTH_ENTRY *) NULL) /* parent realm */ >+ { >+ entry = auth_ent; >+ /* Look for name match. */ >+ if (entry->name[0] == '*') /* this is wildcard realm */ >+ { >+ p = &entry->name[1]; >+ pat_len = strlen (p); >+ head = strlen (u_realm) - pat_len; >+ if (strncmp ((char *) &u_realm[head], >+ (char *) &entry->name[1], pat_len) == 0) >+ { >+ realm_name = u_realm; >+ } >+ else >+ { >+ realm_name = (char *) NULL; >+ } >+ } >+ else /* not a wildcard realm */ >+ { >+ if (strcasecmp (entry->name, u_realm) == 0) >+ { >+ realm_name = entry->name; >+ } >+ } >+ } >+ else /* this entry is an alias name for some real realm */ >+ { >+ entry = auth_ent->parent; >+ /* Look for name match. */ >+ if (entry->name[0] == '*') /* alias in wildcard realm */ >+ { >+ p = &entry->name[1]; >+ pat_len = strlen (p); >+ head = strlen (u_realm) - pat_len; >+ if (strncmp ((char *) &u_realm[head], >+ (char *) &entry->name[1], pat_len) == 0) >+ { >+ /* combine real prefix, parent suffix */ >+ strcpy (temp, u_realm); >+ if (strtok (temp, ".") != (char *) NULL) >+ { >+ realm_name = strcat (temp, >+ &entry->name[1]); >+ } >+ } >+ else >+ { >+ realm_name = (char *) NULL; >+ } >+ } >+ else /* regular alias */ >+ { >+ if (strcasecmp (auth_ent->name, u_realm) == 0) >+ { >+ realm_name = entry->name; >+ } >+ } >+ } >+ >+ if (realm_name != (char *) NULL) /* then we have a name match */ >+ { >+ if (!entry->prot || (entry->prot == prot)) >+ { >+ break; >+ } >+ } >+ } >+ >+ if (auth_ent == (AUTH_ENTRY *) NULL) >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: realm not found", func)); >+ return (AUTH_ENTRY *) NULL; >+ } >+ >+ return entry; >+} /* end of find_auth_ent () */ >+ >+/************************************************************************* >+ * >+ * Function: find_auth_type >+ * >+ * Purpose: Find the proper AUTH_ENTRY to use for the given authentication >+ * realm name from the FILE_LIST entry with the given file_pfx. >+ * >+ * Returns: The authentication type, name of the authentication agent to >+ * use, the primary realm name and any optional packet filter >+ * to be applied are returned. >+ * >+ * Returns: 0 = normal return, >+ * -1 = error return >+ * >+ *************************************************************************/ >+ >+int >+find_auth_type (u_realm, prot, pfx, type, agent, realm, filter) >+ >+char *u_realm; >+int prot; >+char *pfx; >+int *type; /* receives resultant authentication type value */ >+char **agent; /* receives resultant authentication agent name */ >+char **realm; /* receives resultant primary realm name */ >+char **filter; /* receives resultant authentication filter name */ >+ >+{ >+ int head; >+ int pat_len; >+ FILE_LIST *file_ent; >+ AUTH_ENTRY *auth_ent; >+ AUTH_ENTRY *entry; >+ char *p; >+ char *realm_name; >+ static char temp[AUTH_ID_LEN + 1]; >+ static char *func = "find_auth_type"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (u_realm[0] == 0) /* A null realm would match every line. */ >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: NULL realm", func)); >+ return (-1); >+ } >+ >+ if ((file_ent = find_file_ent (pfx)) == (FILE_LIST *) NULL) >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: NULL file_ent", func)); >+ return (-1); >+ } >+ >+ if ((auth_ent = file_ent->auth_list) == (AUTH_ENTRY *) NULL) >+ { >+ /* If no auth_list for this prefix */ >+ file_ent = file_list; >+ /* Default file_ent is first in file_list */ >+ if ((auth_ent = file_ent->auth_list) == (AUTH_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: no default authfile data structure", >+ func); >+ return (-1); >+ } >+ } >+ >+ /* >+ * Match realm name (either exact match or substring match >+ * based on *.realm syntax) with user supplied string. >+ */ >+ for ( ; auth_ent ; auth_ent = auth_ent->next ) >+ { >+ realm_name = (char *) NULL; >+ if (auth_ent->parent == (AUTH_ENTRY *) NULL) /* parent realm */ >+ { >+ entry = auth_ent; >+ /* Look for name match. */ >+ if (entry->name[0] == '*') /* this is wildcard realm */ >+ { >+ p = &entry->name[1]; >+ pat_len = strlen (p); >+ head = strlen (u_realm) - pat_len; >+ if (strncmp ((char *) &u_realm[head], >+ (char *) &entry->name[1], pat_len) == 0) >+ { >+ realm_name = u_realm; >+ } >+ else >+ { >+ realm_name = (char *) NULL; >+ } >+ } >+ else /* not a wildcard realm */ >+ { >+ if (strcasecmp (entry->name, u_realm) == 0) >+ { >+ realm_name = entry->name; >+ } >+ } >+ } >+ else /* this entry is an alias name for some real realm */ >+ { >+ entry = auth_ent->parent; >+ /* Look for name match. */ >+ if (entry->name[0] == '*') /* alias in wildcard realm */ >+ { >+ p = &entry->name[1]; >+ pat_len = strlen (p); >+ head = strlen (u_realm) - pat_len; >+ if (strncmp ((char *) &u_realm[head], >+ (char *) &entry->name[1], pat_len) == 0) >+ { >+ /* combine real prefix, parent suffix */ >+ strcpy (temp, u_realm); >+ if (strtok (temp, ".") != (char *) NULL) >+ { >+ realm_name = strcat (temp, >+ &entry->name[1]); >+ } >+ } >+ else >+ { >+ realm_name = (char *) NULL; >+ } >+ } >+ else /* regular alias */ >+ { >+ if (strcasecmp (auth_ent->name, u_realm) == 0) >+ { >+ realm_name = entry->name; >+ } >+ } >+ } >+ >+ if (realm_name != (char *) NULL) /* then we have a name match */ >+ { >+ if (!entry->prot || (entry->prot == prot)) >+ { >+ break; >+ } >+ } >+ } >+ >+ if (auth_ent == (AUTH_ENTRY *) NULL) >+ { >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: realm not found", func)); >+ return (-1); >+ } >+ >+ *type = entry->type; >+ *agent = entry->host; >+ *realm = realm_name; >+ *filter = entry->filter; >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, >+ "%s: type %d, agent '%s', realm '%s' and filter '%s'", >+ func, entry->type, entry->host, realm_name, entry->filter)); >+ return 0; >+} /* end of find_auth_type () */ >+ >+/************************************************************************* >+ * >+ * Function: find_client >+ * >+ * Purpose: Find the CLIENT_ENTRY in client_list for the client with >+ * the given IP address. If the entry is found, the secret >+ * shared with this client, any configured file_pfx to be >+ * used for this client and the client's name are returned. >+ * >+ * Returns: 0 = found client entry, >+ * -1 = client not found. >+ * >+ *************************************************************************/ >+ >+int >+find_client (ipaddr, hostname, secret, pfx) >+ >+UINT4 ipaddr; >+char **hostname; /* Receives resultant hostname, if found */ >+char **secret; /* Receives resultant secret, if found */ >+char **pfx; /* Receives resultant prefix, if found */ >+ >+{ >+ int ud = 0; >+ CLIENT_ENTRY *client_ent; >+ IP_ADDRESS *an_address; >+ time_t cur_time; >+ static char *func = "find_client"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ cur_time = time (0); >+ for (client_ent = client_list; >+ client_ent; >+ client_ent = client_ent->next) >+ { >+ if (cur_time > client_ent->expire_time) >+ { >+ ud = 1; >+ } >+ >+ for (an_address = client_ent->addrs; >+ an_address != (IP_ADDRESS *) NULL; >+ an_address = an_address->next) >+ { >+ if (an_address->ipaddr.s_addr == ipaddr) >+ { >+ break; >+ } >+ } >+ >+ if (an_address) >+ { >+ break; >+ } >+ } >+ >+ if (ud > 0) >+ { >+ update_clients (); >+ } >+ >+ /* Don't match host-only entries (those with a null secret) */ >+ if (client_ent == (CLIENT_ENTRY *) NULL || *client_ent->secret == '\0') >+ { >+ return (-1); >+ } >+ >+ *hostname = client_ent->hostname; >+ *secret = client_ent->secret; >+ *pfx = client_ent->prefix; >+ >+ return (0); >+} /* end of find_client () */ >+ >+/************************************************************************* >+ * >+ * Function: find_client_by_name >+ * >+ * Purpose: Find the CLIENT_ENTRY in client_list for the client with >+ * the given hostname. If the entry is found, the secret >+ * shared with this client, any configured file_pfx to be >+ * used for this client and the client's name are returned. >+ * >+ * Returns: 0 = found client entry and resolved IP address, >+ * 1 = found client entry but no IP address, >+ * 2 = found host entry but IP address not obtained >+ * (unresolvable DNS name), >+ * -1 = client not found. >+ * >+ *************************************************************************/ >+ >+int >+find_client_by_name (ipaddr, hostname, secret, pfx) >+ >+UINT4 *ipaddr; /* Receives resultant address, if found */ >+char *hostname; /* Match this name */ >+char **secret; /* Receives resultant secret, if found */ >+char **pfx; /* Receives resultant prefix, if found */ >+ >+{ >+ int ud = 0; >+ CLIENT_ENTRY *client_ent; >+ DNS_NAME *name_ent; >+ char *name; >+ time_t cur_time; >+ static char *func = "find_client_by_name"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (good_ipaddr (hostname) == 0) >+ { >+ /* name = address same as find_client() call */ >+ *ipaddr = ntohl(inet_addr (hostname)); >+ return find_client (*ipaddr, &name, secret, pfx); >+ } >+ >+ if (strcmp (hostname, RADIUS_LOCALSERVER) == 0) >+ { >+ hostname = ourhostname; >+ } >+ >+ cur_time = time (0); >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_ent->next) >+ { >+ if (cur_time > client_ent->expire_time) >+ { >+ ud = 1; >+ } >+ >+ if (strcmp (client_ent->hostname, hostname) == 0) >+ { >+ break; >+ } >+ >+ for (name_ent = client_ent->names; >+ name_ent != (DNS_NAME *) NULL; >+ name_ent = name_ent->next) >+ { >+ if (strcmp (name_ent->name, hostname) == 0) >+ { >+ break; >+ } >+ } >+ >+ if (name_ent != (DNS_NAME *) NULL) >+ { >+ break; >+ } >+ } >+ >+ if (ud > 0) >+ { >+ update_clients (); >+ } >+ >+ /* Don't match host-only entries (those with a null secret) */ >+ if (client_ent == (CLIENT_ENTRY *) NULL || *client_ent->secret == '\0') >+ { >+ return (-1); >+ } >+ >+ *secret = client_ent->secret; >+ *pfx = client_ent->prefix; >+ >+ if (client_ent->addrs == (IP_ADDRESS *) NULL) >+ { >+ *ipaddr = 0; >+ return (1); >+ } >+ >+ if ((*ipaddr = client_ent->addrs->ipaddr.s_addr) == -1) >+ { >+ return (2); >+ } >+ >+ return (0); >+} /* end of find_client_by_name () */ >+ >+/************************************************************************* >+ * >+ * Function: find_host_by_name >+ * >+ * Purpose: Resolve the host address by looking in the client list. >+ * Non-clients (those with a null secret) in this list >+ * are matched as well as normal clients. >+ * >+ * Returns: 0 = found host entry and resolved IP address, >+ * 1 = found host entry but unresolved IP address, >+ * 2 = found host entry but IP address not obtained >+ * (unresolvable DNS name - uses address 255.255.255.255), >+ * -1 = host not found. >+ * >+ *************************************************************************/ >+ >+int >+find_host_by_name (ipaddr, hostname) >+ >+UINT4 *ipaddr; /* receives resultant address if found */ >+char *hostname; /* Match this name */ >+ >+{ >+ int ud = 0; >+ char *p; >+ char *q; >+ CLIENT_ENTRY *client_ent; >+ DNS_NAME *name_ent; >+ time_t cur_time; >+ static char *func = "find_host_by_name"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (good_ipaddr (hostname) == 0) >+ { >+ *ipaddr = ntohl(inet_addr (hostname)); >+ return 0; >+ } >+ >+ if (strcmp (hostname, RADIUS_LOCALSERVER) == 0) >+ { >+ *ipaddr = self_ip[0]; >+ return 0; >+ } >+ >+ /* See if it's us. Match full name or up to "." of our name */ >+ for (p = hostname, q = ourhostname; *p == *q; p++, q++) >+ { >+ if (*p == '\0') >+ { >+ break; >+ } >+ } >+ >+ if (*p == '\0' && (*q == '\0' || *q == '.')) >+ { >+ *ipaddr = self_ip[0]; >+ return 0; >+ } >+ >+ cur_time = time (0); >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_ent->next) >+ { >+ if (cur_time > client_ent->expire_time) >+ { >+ ud = 1; >+ } >+ >+ if (strcmp (client_ent->hostname, hostname) == 0) >+ { >+ break; >+ } >+ >+ for (name_ent = client_ent->names; >+ name_ent != (DNS_NAME *) NULL; >+ name_ent = name_ent->next) >+ { >+ if (strcmp (name_ent->name, hostname) == 0) >+ { >+ break; >+ } >+ } >+ >+ if (name_ent != (DNS_NAME *) NULL) >+ { >+ break; >+ } >+ } >+ >+ if (ud > 0) >+ { >+ update_clients (); >+ } >+ >+ if (client_ent == (CLIENT_ENTRY *) NULL) >+ { >+ *ipaddr = 0; >+ return (-1); >+ } >+ >+ if (client_ent->addrs == (struct ip_address *) NULL) >+ { >+ *ipaddr = 0; >+ return (1); >+ } >+ >+ if ((*ipaddr = client_ent->addrs->ipaddr.s_addr) == -1) >+ { >+ return (2); >+ } >+ return (0); >+} /* end of find_host_by_name () */ >+ >+/************************************************************************* >+ * >+ * Function: find_file_ent >+ * >+ * Purpose: Find a FILE_LIST entry on file_list with the specified >+ * file_pfx. The entry should be found as find_file_ent is >+ * only called for file_pfx's that were found in the "clients" >+ * file at initialization time. >+ * >+ *************************************************************************/ >+ >+static FILE_LIST * >+find_file_ent (file_pfx) >+ >+char *file_pfx; >+ >+{ >+ FILE_LIST *file_ent; >+ static char *func = "find_file_ent"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if ((file_ent = file_list) == (FILE_LIST *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: No users/authfile data structure", func); >+ return (FILE_LIST *) NULL; >+ } >+ if (file_pfx && file_pfx[0]) >+ { >+ while (strcmp (file_ent->prefix, file_pfx) != 0) >+ { >+ if ((file_ent = file_ent->next) == (FILE_LIST *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Couldn't match %s in FILE_LIST", >+ func, file_pfx); >+ return (FILE_LIST *) NULL; >+ } >+ } >+ } >+ return file_ent; >+} /* end of find_file_ent () */ >+ >+/************************************************************************* >+ * >+ * Function: free_clients >+ * >+ * Purpose: Toss client list entries and associated address structure. >+ * >+ * Remark: Zap storage blocks to avoid leaving any secrets around. >+ * >+ *************************************************************************/ >+ >+static void >+free_clients (client_list) >+ >+CLIENT_ENTRY *client_list; >+ >+{ >+ CLIENT_ENTRY *client_ent; >+ IP_ADDRESS *an_address; >+ DNS_NAME *a_name; >+ static char *func = "free_clients"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_list) >+ { >+ client_list = client_ent->next; >+ >+ for (an_address = client_ent->addrs; >+ an_address != (IP_ADDRESS *) NULL; >+ an_address = client_ent->addrs) >+ { >+ client_ent->addrs = an_address->next; >+ free (an_address); >+ } >+ >+ for (a_name = client_ent->names; >+ a_name != (DNS_NAME *) NULL; >+ a_name = client_ent->names) >+ { >+ client_ent->names = a_name->next; >+ free (a_name); >+ } >+ >+ free (client_ent); >+ } >+ return; >+} /* end of free_clients () */ >+ >+/************************************************************************* >+ * >+ * Function: free_file_lists >+ * >+ * Purpose: Free all the storage for the "users" and "authfile" >+ * memory resident data structures allocated by calling >+ * config_files(). >+ * >+ *************************************************************************/ >+ >+static void >+free_file_lists () >+ >+{ >+ FILE_LIST *file_ent; >+ USER_ENTRY *user_ent; >+ AUTH_ENTRY *auth_ent; >+ static char *func = "free_file_lists"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ authfile_cnt = 0; >+ users_cnt = 0; >+ >+ for (file_ent = file_list; file_ent; file_ent = file_list) >+ { >+ for (user_ent = file_ent->user_list; >+ user_ent; >+ user_ent = file_ent->user_list) >+ { >+ file_ent->user_list = user_ent->next; >+ free_user_ent (user_ent); >+ } >+ for (auth_ent = file_ent->auth_list; >+ auth_ent; >+ auth_ent = file_ent->auth_list) >+ { >+ file_ent->auth_list = auth_ent->next; >+ free (auth_ent); >+ } >+ file_list = file_ent->next; >+ free (file_ent); >+ } >+ >+ return; >+} /* end of free_file_lists () */ >+ >+/************************************************************************* >+ * >+ * Function: free_user_ent >+ * >+ * Purpose: Free all components of a USER_ENTRY structure. Zap >+ * the USER_ENTRY storage. >+ * >+ *************************************************************************/ >+ >+void >+free_user_ent (user_ent) >+ >+USER_ENTRY *user_ent; >+ >+{ >+ list_free (user_ent->check); >+ list_free (user_ent->reply); >+ memset ((char *) user_ent, '\0', sizeof (USER_ENTRY)); >+ free (user_ent); >+ return; >+} /* end of free_user_ent () */ >+ >+/************************************************************************* >+ * >+ * Function: get_our_addr >+ * >+ * Purpose: A global function to return a local variable (?) >+ * >+ * Returns: (an) IP address of this machine. >+ * >+ *************************************************************************/ >+ >+UINT4 >+get_our_addr () >+ >+{ >+ return self_ip[0]; >+} /* end of get_our_addr () */ >+ >+/************************************************************************* >+ * >+ * Function: host_is_us >+ * >+ * Purpose: Determine if we are the given host. >+ * >+ * Returns: 1 if the given hostname is the name of this host, >+ * 0 otherwise. >+ * >+ *************************************************************************/ >+ >+static int >+host_is_us (hostname) >+ >+char *hostname; >+ >+{ >+ UINT4 addr; >+ UINT4 *adptr; >+ >+ if (find_host_by_name (&addr, hostname) == 0) >+ { >+ for (adptr = self_ip; *adptr > 0; adptr++) >+ { >+ if (*adptr == addr) >+ { >+ return 1; >+ } >+ } >+ } >+ return 0; >+} /* end of host_is_us () */ >+ >+/************************************************************************* >+ * >+ * Function: insert_client >+ * >+ * Purpose: Inserts a CLIENT_ENTRY node into client_list for the >+ * given hostname. >+ * >+ * Returns: 0 - inserted ok >+ * -1 - bad news >+ * >+ *************************************************************************/ >+ >+static int >+insert_client (hostname, secret, prefix) >+ >+char *hostname; >+char *secret; >+char *prefix; >+ >+{ >+ CLIENT_ENTRY *client_ent = (CLIENT_ENTRY *) NULL; >+ CLIENT_ENTRY *oldent; >+ CLIENT_ENTRY **prev; >+ IP_ADDRESS *ip_address; >+ struct in_addr addr; >+ static char *func = "insert_client"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ /* Convert generic name for us to our real name */ >+ if (strcmp (hostname, RADIUS_LOCALSERVER) == 0) >+ { >+ hostname = ourhostname; >+ } >+ >+ /* Look for entry from previous list (before HUP) */ >+ >+ if (old_clients != (CLIENT_ENTRY *) NULL) >+ { >+ for (prev = &old_clients; >+ (oldent = *prev) != (CLIENT_ENTRY *) NULL; >+ prev = &oldent->next) >+ { >+ if (strcmp (hostname, oldent->hostname) == 0) >+ { >+ /* Matched - Remove from old list */ >+ *prev = oldent->next; >+ client_ent = oldent; >+ break; >+ } >+ } >+ } >+ >+ if (client_ent == (CLIENT_ENTRY *) NULL) >+ { >+ if ((client_ent = >+ (CLIENT_ENTRY *) malloc ( sizeof (CLIENT_ENTRY))) >+ == (CLIENT_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL Couldn't allocate CLIENT_ENTRY storage", >+ func); >+ abort (); >+ } >+ client_ent->hostname = add_string (hostname, ASIS); >+ client_ent->names = (DNS_NAME *) NULL; >+ client_ent->addrs = (IP_ADDRESS *) NULL; >+ client_ent->type = CE_DNS; >+ >+ /* Set constant addrs now so we don't have to wait for DNS */ >+ if (good_ipaddr (hostname) == 0) >+ { >+ client_ent->type = CE_NUMERIC; >+ addr.s_addr = ntohl(inet_addr (hostname)); >+ } >+ else >+ { >+ if (strcmp (hostname, ourhostname) == 0) >+ { >+ client_ent->type = CE_OURADDR; >+ addr.s_addr = self_ip[0]; >+ } >+ } >+ >+ if (client_ent->type != CE_DNS) >+ { >+ if ((ip_address = >+ (IP_ADDRESS *) malloc (sizeof (CLIENT_ENTRY))) >+ == (IP_ADDRESS *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL Couldn't allocate IP_ADDRESS storage", >+ func); >+ abort (); >+ } >+ >+ ip_address->ipaddr = addr; >+ ip_address->next = (IP_ADDRESS *) NULL; >+ client_ent->addrs = ip_address; >+ } >+ } >+ >+ client_ent->secret = add_string (secret, ASIS); >+ client_ent->prefix = add_string (prefix, ASIS); >+ client_ent->expire_time = (time_t) 0; >+ client_ent->next = client_list; >+ client_list = client_ent; >+ >+ /* >+ * If the entry had an optional file prefix, add a new FILE_ENTRY >+ * to the file_list to handle this prefix. Add_file_list() will >+ * not add duplicate entries. >+ */ >+ if (client_ent->prefix[0] != '\0') >+ { >+ add_file_list (client_ent->prefix); >+ } >+ return 0; >+} /* end of insert_client () */ >+ >+#define MAX_HOSTNAME_BUFFERS 20 >+ >+/************************************************************************* >+ * >+ * Function: ip_hostname >+ * >+ * Purpose: Return a printable host name (or IP address in dotted quad >+ * notation) for the supplied IP address. >+ * >+ *************************************************************************/ >+ >+char * >+ip_hostname (h_ipaddr) >+ >+UINT4 h_ipaddr; >+ >+{ >+ UINT4 *ourad; >+ CLIENT_ENTRY *client_ent; >+ IP_ADDRESS *an_address; >+ DNS_NAME *a_name; >+ struct hostent *hp; >+ struct in_addr inad; >+ static char buffers[MAX_HOSTNAME_BUFFERS][128]; >+ static int ndx = 0; >+ char *hstname = buffers[ndx]; >+ >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_ent->next) >+ { >+ for (an_address = client_ent->addrs; >+ an_address != (IP_ADDRESS *) NULL; >+ an_address = an_address->next) >+ { >+ if (an_address->ipaddr.s_addr == h_ipaddr) >+ { >+ break; >+ } >+ } >+ >+ if (an_address != (IP_ADDRESS *) NULL) >+ { >+ break; >+ } >+ } >+ >+ if (client_ent != (CLIENT_ENTRY *) NULL) >+ { >+ /* >+ * We found something in our tables. >+ * Return a pointer to that instead of >+ * copying it to our own static area. >+ */ >+ if ((a_name = client_ent->names) == (DNS_NAME *) NULL || >+ (a_name->type != 0)) >+ { >+ return (client_ent->hostname); >+ } >+ else /* return official name if it's not in the main entry */ >+ { >+ return (a_name->name); >+ } >+ } >+ >+ /* Didn't find it in our tables. Keep looking... */ >+ for (ourad = self_ip; >+ (*ourad > (UINT4) 0) && (*ourad != h_ipaddr); >+ ourad++) >+ { >+ continue; >+ } >+ >+ /* If it was our own address, return our hostname. */ >+ if (*ourad > (UINT4) 0) >+ { >+ return (ourhostname); >+ } >+ >+ /* It wasn't us, so make something up. */ >+ inad.s_addr = htonl(h_ipaddr); >+ strcpy (hstname, inet_ntoa (inad)); /* xxx.yyy.zzz.qqq */ >+ >+ /* >+ * Special check for non-server use. >+ * Note: a server always will have at >+ * least one client. >+ */ >+ if (client_list == (CLIENT_ENTRY *) NULL) >+ { >+ if ((hp = gethostbyaddr ((char *) &inad.s_addr, >+ sizeof (struct in_addr), >+ AF_INET)) >+ != (struct hostent *) NULL) >+ { >+ strcpy (hstname, hp->h_name); >+ } >+ } >+ >+ /* Circulate through the buffers... */ >+ ndx++; >+ if (ndx >= MAX_HOSTNAME_BUFFERS) >+ { >+ ndx = 0; >+ } >+ >+ return (hstname); >+ >+} /* end of ip_hostname () */ >+ >+/************************************************************************* >+ * >+ * Function: list_cat >+ * >+ * Purpose: Given two lists, "a" and "b", place "b" at the end of "a" >+ * >+ *************************************************************************/ >+ >+void >+list_cat (a, b) >+ >+VALUE_PAIR **a; >+VALUE_PAIR *b; >+ >+{ >+ VALUE_PAIR **last; >+ FILE *debugout = stdout; >+ static char *func = "list_cat"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (debug_flag >= 4) >+ { >+ if (ddt) >+ { >+ debugout = ddt; >+ } >+ fprintf (debugout, "First list:\n"); >+ } >+ >+ for (last = a; *last != (VALUE_PAIR *) NULL; last = &((*last)->next)) >+ { >+ if (debug_flag >= 4) >+ { >+ debug_pair (debugout, *last); >+ } >+ } >+ >+ *last = b; >+ >+ if (debug_flag >= 4) >+ { >+ fprintf (debugout, "and Second list:\n"); >+ debug_list (debugout, b); >+ } >+ >+ return; >+} /* end of list_cat () */ >+ >+#define LIST_COPY_LIMIT 256 /* Limit the number of items we will copy. */ >+ >+/************************************************************************* >+ * >+ * Function: list_copy >+ * >+ * Purpose: Make a copy of the entire list of value_pairs pointed to by >+ * from_list. It is necessary to copy the check_items and >+ * reply_items from a USER_ENTRY before processing a request >+ * because they may be modified or freed. >+ * >+ *************************************************************************/ >+ >+void >+list_copy (to_list, from_list) >+ >+VALUE_PAIR **to_list; >+VALUE_PAIR *from_list; >+ >+{ >+ int count = 0; /* Count items we copy. */ >+ VALUE_PAIR *copy_item; >+ VALUE_PAIR *new_item; >+ VALUE_PAIR **last; >+ VALUE_PAIR **old_end; >+ static char *func = "list_copy"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (to_list == (VALUE_PAIR **) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: NULL parameter", func); >+ exit (-13); >+ } >+ >+ copy_item = (VALUE_PAIR *) NULL; >+ >+ /* run to end of destination list */ >+ for (last = to_list ; >+ *last != (VALUE_PAIR *) NULL ; >+ last = &((*last)->next)) >+ { >+ if (*last == from_list) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL (0x%p->0x%p,0x%p) crosslinked at 0x%p->0x%p", >+ func, to_list, *to_list, from_list, last, *last); >+ dumpcore = 1; >+ abort (); >+ } >+ } >+ old_end = last; /* Save old end-ptr for sanity checking. */ >+ >+ new_item = (VALUE_PAIR *) NULL; >+ >+ dprintf(5, (LOG_AUTH, LOG_DEBUG, >+ "%s: copy from list 0x%p to end of list at 0x%p->0x%p", >+ func, from_list, to_list, *to_list)); >+ >+ for (copy_item = from_list ; >+ copy_item != (VALUE_PAIR *) NULL ; >+ copy_item = copy_item->next) >+ { >+ if (count > LIST_COPY_LIMIT) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL (0x%p->0x%p, 0x%p), count=%d, limit exceed", >+ func, to_list, *to_list, from_list, copy_item, >+ count); >+ dumpcore = 1; >+ abort (); >+ } >+ >+ if (copy_item == *old_end) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL (0x%X->0x%X, 0x%X) list appended to itself at 0x%X", >+ func, to_list, *to_list, from_list, copy_item); >+ dumpcore = 1; >+ abort (); >+ } >+ >+ if ((new_item = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) >+ == (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, "%s: FATAL out of memory", >+ func); >+ abort (); >+ } >+ memcpy ((char *) new_item, (char *) copy_item, >+ sizeof (VALUE_PAIR)); >+ new_item->next = (VALUE_PAIR *) NULL; >+ >+ *last = new_item; /* always put copy at end of to_list */ >+ last = &(new_item->next); /* new end of to_list */ >+ count++; >+ } >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: copied %d items", func, count)); >+ return; >+} /* end of list_copy () */ >+ >+#define PARSE_MODE_NAME 0 >+#define PARSE_MODE_EQUAL 1 >+#define PARSE_MODE_VALUE 2 >+#define PARSE_MODE_INVALID 3 >+ >+/************************************************************************* >+ * >+ * Function: pair_parse >+ * >+ * Purpose: Parses the buffer to extract the attribute-value pairs. >+ * >+ * Returns: 0 = successful parse of attribute-value pair, >+ * -1 = syntax (or other) error detected. >+ * >+ *************************************************************************/ >+ >+int >+pair_parse (buffer, first_pair) >+ >+char *buffer; >+VALUE_PAIR **first_pair; >+ >+{ >+ int mode; >+ int rc; >+ char attrstr[AUTH_ID_LEN]; >+ char valstr[AUTH_ID_LEN]; >+ DICT_ATTR *attr; >+ DICT_VALUE *dval; >+ VALUE_PAIR *pair; >+ VALUE_PAIR *link; >+ struct tm *tm; >+ time_t timeval; >+ static char *func = "pair_parse"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ mode = PARSE_MODE_NAME; >+ while (*buffer != '\n' && *buffer != '\0') >+ { >+ if (*buffer == ' ' || *buffer == '\t' || *buffer == ',') >+ { >+ buffer++; >+ continue; >+ } >+ >+ switch (mode) >+ { >+ case PARSE_MODE_NAME: /* Attribute Name */ >+ fieldcpy (attrstr, &buffer); >+ if ((attr = >+ dict_attrfind (attrstr)) == (DICT_ATTR *) NULL) >+ { >+ return (-1); >+ } >+ mode = PARSE_MODE_EQUAL; >+ break; >+ >+ case PARSE_MODE_EQUAL: /* Equal sign */ >+ if (*buffer == '=') >+ { >+ mode = PARSE_MODE_VALUE; >+ buffer++; >+ } >+ else >+ { >+ return (-1); >+ } >+ break; >+ >+ case PARSE_MODE_VALUE: /* Value */ >+ fieldcpy (valstr, &buffer); >+ >+ if ((pair = >+ (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) >+ == (VALUE_PAIR *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: FATAL out of memory", func); >+ abort (); >+ } >+ strcpy (pair->name, attr->name); >+ pair->attribute = attr->value; >+ pair->type = attr->type; >+ >+ switch (pair->type) >+ { >+ >+ case PW_TYPE_STRING: >+ strcpy (pair->strvalue, valstr); >+ break; >+ >+ case PW_TYPE_INTEGER: >+ if (isdigit (*valstr)) >+ { >+ pair->lvalue = atoi (valstr); >+ } >+ else >+ { >+ if ((dval = dict_valfind (valstr)) >+ == (DICT_VALUE *) NULL) >+ { >+ free (pair); >+ return (-1); >+ } >+ else >+ { >+ pair->lvalue = dval->value; >+ } >+ } >+ break; >+ >+ case PW_TYPE_IPADDR: >+ rc = find_host_by_name (&pair->lvalue, valstr); >+ if (rc == -1) /* Name not in our list yet */ >+ { >+ insert_client (valstr, "", ""); >+ } >+ else >+ { >+ if (rc == 2) /* Unresolvable DNS name */ >+ { >+ free (pair); >+ return (-1); >+ } >+ } >+ >+ /* If DNS name given, store it in strvalue */ >+ if (good_ipaddr (valstr) == 0) >+ { >+ *pair->strvalue = '\0'; >+ } >+ else /* Now we can re-resolve these names */ >+ { >+ strcpy (pair->strvalue, valstr); >+ } >+ break; >+ >+ case PW_TYPE_DATE: >+ timeval = time (0); >+ tm = localtime (&timeval); >+ tm->tm_hour = 0; >+ tm->tm_min = 0; >+ tm->tm_sec = 0; >+ user_gettime (valstr, tm); >+#ifdef TIMELOCAL >+ pair->lvalue = (UINT4) timelocal (tm); >+#else /* TIMELOCAL */ >+ pair->lvalue = (UINT4) mktime (tm); >+#endif /* TIMELOCAL */ >+ break; >+ >+ default: >+ free (pair); >+ return (-1); >+ } >+ pair->next = (VALUE_PAIR *) NULL; >+ >+ if (*first_pair == (VALUE_PAIR *) NULL) >+ { >+ *first_pair = pair; >+ } >+ else >+ { >+ link = *first_pair; >+ while (link->next != (VALUE_PAIR *) NULL) >+ { >+ link = link->next; >+ } >+ link->next = pair; >+ } >+ >+ mode = PARSE_MODE_NAME; >+ break; >+ >+ default: >+ mode = PARSE_MODE_NAME; >+ break; >+ } >+ } >+ return (0); >+} /* end of pair_parse () */ >+ >+/************************************************************************* >+ * >+ * Function: read_auth >+ * >+ * Purpose: Reads in the realm information from the "authfile" with >+ * file_pfx corresponding to the given file_ent. The information >+ * read is copied to a data structure that is linked to the >+ * given file_ent. >+ * >+ *************************************************************************/ >+ >+static int >+read_auth (file_ent, dolog) >+ >+FILE_LIST *file_ent; >+int dolog; >+ >+{ >+ FILE *authfd; >+ char *name; >+ char *prot; >+ char *type; >+ char *host; >+ char *filter; >+ char *alias_list; >+ int line_no = 0; >+ int ent_cnt = 0; >+ int type_inx; >+ int prot_inx; >+ int error = 0; >+ AUTH_ENTRY *auth_ent; >+ AUTH_ENTRY **end_ent; >+ AUTH_ALIAS_ENTRY *alias_ent; >+ DICT_VALUE *type_val; >+ static char *auth_prots[] = >+ { >+ PW_PROTTYPES_DFLT, >+ PW_PROTTYPES_CHAP, >+ PW_PROTTYPES_PW, >+ NULL >+ }; >+ char buffer[128]; >+ char fname[MAXPATHLEN]; >+ char *func = "read_auth"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ sprintf (fname, "%s/%s%s", radius_dir, file_ent->prefix, RADIUS_AUTH); >+ if ((authfd = fopen (fname, "r")) == (FILE *) NULL) >+ { >+ /* >+ * It's okay if a non-prefixed RADIUS_AUTH file doesn't exist, >+ * as long as no CI_AUTHENTICATION_TYPE = REALM entries are >+ * configured in the RADIUS_USERS file. If <pfx>RADIUS_AUTH >+ * doesn't exist, then the non-prefixed RADIUS_AUTH file will >+ * be used instead. >+ */ >+ return (0); >+ } >+ end_ent = &file_ent->auth_list; >+ while (fgets (buffer, sizeof (buffer), authfd) != (char *) NULL) >+ { >+ line_no++; >+ if (isspace (*buffer) || (*buffer == COMMENT)) >+ { >+ continue; >+ } >+ name = strtok (buffer, " ,\t\n\r"); >+ >+ if (strcmp ("DEFAULT_RADIUS_SERVER", name) == 0) >+ { >+ if ((host = strtok (NULL, " \"\n\r")) != (char *) NULL) >+ { >+ strcpy (default_radius_server, host); >+ } >+ else >+ { >+ default_radius_server[0] = '\0'; >+ } >+ continue; >+ } >+ else >+ { >+ if (strcmp ("DEFAULT_TACACS_SERVER", name) == 0) >+ { >+ if ((host = strtok (NULL, " \"\n\r")) >+ != (char *) NULL) >+ { >+ strcpy (default_tacacs_server, host); >+ } >+ else >+ { >+ default_tacacs_server[0] = '\0'; >+ } >+ continue; >+ } >+ } >+ >+ /* Scan for optional alias list or protocol indicator */ >+ >+ prot_inx = 0; >+ alias_list = NULL; >+ type = NULL; >+ >+ while (type == NULL && !error) >+ { >+ prot = strtok (NULL, " ,\t\n\r"); >+ if (prot == NULL) >+ { >+ error++; >+ continue; >+ } >+ >+ >+ switch (*prot) >+ { >+ case '(': /* "(<aliases>)" */ >+ alias_list = prot; >+ if (prot[strlen (prot) - 1] != ')') >+ { >+ if (strtok (NULL, ")") == NULL) >+ { >+ error++; >+ } >+ /* We don't want to break up alias list yet */ >+ prot[strlen (prot)] = ' '; >+ } >+ break; >+ >+ case ('-'): /* "-<protocol>" */ >+ if (*++prot == '\0') >+ { >+ error++; >+ break; >+ } >+ >+ for (prot_inx = 0; >+ auth_prots[prot_inx] && >+ strcmp (prot, auth_prots[prot_inx]) != 0; >+ prot_inx++) >+ { >+ ; >+ } >+ >+ if (!auth_prots[prot_inx]) >+ { >+ error++; >+ } >+ break; >+ >+ default: >+ type = prot; >+ break; >+ } >+ } >+ >+ if (error) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Invalid entry in %s at line %d", >+ func, fname, line_no); >+ continue; >+ } >+ >+ type_val = dict_valfind (type); >+ if (type_val == (DICT_VALUE *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Invalid TYPE '%s' in %s at line %d", >+ func, type, fname, line_no); >+ continue; >+ } >+ type_inx = type_val->value; >+ >+ host = strtok (NULL, " \t\n\r"); >+ filter = strtok (NULL, " \t\n\r"); >+ >+ if (host == NULL && type_inx != AA_UNIX) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Invalid entry in %s at line %d", >+ func, fname, line_no); >+ continue; >+ } >+ >+ if ((auth_ent = (AUTH_ENTRY *) malloc (sizeof (AUTH_ENTRY))) >+ == (AUTH_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: No memory for auth_ent", func); >+ fclose (authfd); >+ return (-1); >+ } >+ auth_ent->parent = (AUTH_ENTRY *) NULL; >+ auth_ent->type = type_inx; >+ >+ if (is_engine == 1) /* then we are being called by the engine */ >+ { >+ if (authtype_tv[type_inx] == (AATV *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Missing AATV for entry on line %d of %s", >+ func, line_no, fname); >+ fclose (authfd); >+ return (-1); >+ } >+ } >+ >+ auth_ent->prot = prot_inx; >+ auth_ent->name = add_string (name, ASIS); >+ auth_ent->host = add_string (host, ASIS); >+ auth_ent->filter = add_string (filter, ASIS); >+ auth_ent->next = (AUTH_ENTRY *) NULL; >+ *end_ent = auth_ent; >+ end_ent = &auth_ent->next; >+ ent_cnt++; >+ >+ /* Add alias entries if aliases given */ >+ if (alias_list) >+ { >+ alias_list++; >+ name = strtok (alias_list, " ,)"); >+ while (name) >+ { >+ if ((alias_ent = >+ (AUTH_ALIAS_ENTRY *) malloc >+ (sizeof(AUTH_ALIAS_ENTRY)) ) >+ == (AUTH_ALIAS_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: No memory for auth_ent", >+ func); >+ fclose (authfd); >+ return (-1); >+ } >+ alias_ent->name = add_string (name, ASIS); >+ alias_ent->parent = auth_ent; >+ alias_ent->next = (AUTH_ENTRY *) NULL; >+ *end_ent = (AUTH_ENTRY *) alias_ent; >+ end_ent = &alias_ent->next; >+ name = strtok (NULL, " ,)"); >+ } >+ } >+ } >+ fclose (authfd); >+ if (dolog) >+ { >+ logit (LOG_DAEMON, LOG_INFO, >+ "%s: %s (%u entries) read to memory", >+ func, fname, ent_cnt); >+ } >+ authfile_cnt += ent_cnt; >+ >+ return 0; >+} /* end of read_auth () */ >+ >+#define FIND_MODE_NAME 0 >+#define FIND_MODE_REPLY 1 >+#define FIND_MODE_SKIP 2 >+#define FIND_MODE_FLUSH 3 >+ >+/************************************************************************* >+ * >+ * Function: read_users >+ * >+ * Purpose: For each entry in a "users" file (with the file_pfx >+ * corresponding to the given file_ent), read all check_items >+ * and reply_items into a data structure. Each such >+ * data structure is linked to the given file_ent. >+ * >+ * Returns: 0 = normal (successful) return, >+ * -1 = error return. >+ * >+ *************************************************************************/ >+ >+static int >+read_users (file_ent, dolog) >+ >+FILE_LIST *file_ent; >+int dolog; >+ >+{ >+ FILE *userfd; >+ char *ptr; >+ int mode; >+ int line_nbr = 0; >+ int count = 0; >+ USER_ENTRY *user_ent = (USER_ENTRY *) NULL; >+ USER_ENTRY **end_ent; >+ char buffer[256]; >+ char fname[MAXPATHLEN]; >+ static char *func = "read_users"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ /* >+ * Open the user table >+ */ >+ sprintf (fname, "%s/%s%s", radius_dir, file_ent->prefix, RADIUS_USERS); >+ if ((userfd = fopen (fname, "r")) == (FILE *) NULL) >+ { >+ /* >+ * It's ok for prefixed user files to not exist, but >+ * non-prefixed user file has to exist. >+ */ >+ if (file_ent->prefix[0] == 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Couldn't open %s for reading", >+ func, fname); >+ return (-1); >+ } >+ return (0); >+ } >+ >+ end_ent = &file_ent->user_list; >+ >+ mode = FIND_MODE_NAME; >+ while (fgets (buffer, sizeof (buffer), userfd) != (char *) NULL) >+ { >+ line_nbr++; >+ if (*buffer == COMMENT) >+ { >+ continue; >+ } >+ >+ for (;;) >+ { >+ if (mode == FIND_MODE_NAME) >+ { >+ if (isspace (*buffer)) >+ { >+ break; /* to read another line */ >+ } >+ if ((user_ent = (USER_ENTRY *) >+ malloc (sizeof (USER_ENTRY))) >+ == (USER_ENTRY *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ALERT, >+ "%s: Couldn't allocate USER_ENTRY storage", >+ func); >+ return (-1); >+ } >+ ptr = strtok (buffer, " \t\n\r"); >+ user_ent->name = add_string (ptr, ASIS); >+ user_ent->check = (VALUE_PAIR *) NULL; >+ user_ent->reply = (VALUE_PAIR *) NULL; >+ user_ent->next = (USER_ENTRY *) NULL; >+ >+ /* >+ * Parse the check values >+ */ >+ ptr += strlen (ptr) + 1; >+ if (pair_parse (ptr, &user_ent->check) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: %d: Parse error for user %s (check)", >+ func, line_nbr, user_ent->name); >+ free_user_ent (user_ent); >+ user_ent = (USER_ENTRY *) NULL; >+ } >+ else >+ { >+ mode = FIND_MODE_REPLY; >+ } >+ break; /* to read another line */ >+ } >+ >+ /* Reading reply items */ >+ if (isspace (*buffer)) >+ { >+ /* >+ * Parse the reply values >+ */ >+ if (pair_parse (buffer, &user_ent->reply) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: %d: Parse error for user %s (reply)", >+ func, line_nbr, user_ent->name); >+ free_user_ent (user_ent); >+ user_ent = (USER_ENTRY *) NULL; >+ mode = FIND_MODE_NAME; >+ } >+ break; >+ } >+ >+ /* Start of next entry */ >+ *end_ent = user_ent; >+ end_ent = &user_ent->next; >+ user_ent = (USER_ENTRY *) NULL; >+ mode = FIND_MODE_NAME; >+ count++; >+ continue; /* with same input */ >+ } >+ } >+ fclose (userfd); >+ if (user_ent != (USER_ENTRY *) NULL) >+ { >+ *end_ent = user_ent; >+ count++; >+ } >+ >+ if (dolog) >+ { >+ logit (LOG_DAEMON, LOG_INFO, >+ "%s: %s (%u entries) read to memory", >+ func, fname, count); >+ } >+ users_cnt += count; >+ >+ return (0); >+} /* end of read_users () */ >+ >+/************************************************************************* >+ * >+ * Function: return_file_list >+ * >+ * Purpose: Returns the private file_list pointer for clients in need. >+ * >+ *************************************************************************/ >+ >+FILE_LIST * >+return_file_list () >+ >+{ >+ return (file_list); >+} /* end of return_file_list () */ >+ >+/************************************************************************* >+ * >+ * Function: update_clients >+ * >+ * Purpose: Updates IP address(es) and expire_time in given >+ * CLIENT_ENTRY node. >+ * >+ *************************************************************************/ >+ >+int >+update_clients () >+ >+{ >+ int len; >+ int notify_count = 0; >+ struct hostent *hp; >+ struct in_addr **addrlist; >+ char *aliascnt; >+ char *ptr; >+ char **name; >+ CLIENT_ENTRY *client_ent; >+ struct sockaddr_in send_sin; >+ time_t cur_time; >+ static char *func = "update_clients"; >+ >+ dprintf(4, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ if (dnspid != 0) /* Already resolving addrs */ >+ { >+ return 0; >+ } >+ >+ if (spawn_flag > 0) >+ { >+ if ((dnspid = (int) fork ()) < 0) >+ { >+ dnspid = 0; >+ logit (LOG_DAEMON, LOG_ALERT, "%s: fork: %s", >+ func, get_errmsg ()); >+ return (-1); >+ } >+ >+ if (dnspid != 0) /* Parent */ >+ { >+ return 0; >+ } >+ } >+ >+ /* ======= Child process code ======= */ >+ >+ memset ((char *) &send_sin, '\0', sizeof (send_sin)); >+ send_sin.sin_family = AF_INET; >+ send_sin.sin_addr.s_addr = htonl(self_ip[0]); >+ send_sin.sin_port = htons(rad_ipc_port); >+ >+ cur_time = time (0); >+ for (client_ent = client_list; >+ client_ent != (CLIENT_ENTRY *) NULL; >+ client_ent = client_ent->next) >+ { >+ if (cur_time < client_ent->expire_time) >+ { >+ continue; >+ } >+ >+ hp = gethostbyname (client_ent->hostname); >+ ptr = send_buffer; >+ *ptr++ = '\0'; /* Only one code for now */ >+ strcpy (ptr, client_ent->hostname); >+ ptr += strlen (ptr) + 1; >+ *ptr = '\0'; >+ aliascnt = ptr++; >+ >+ if (hp != (struct hostent *) NULL) >+ { >+ if (hp->h_aliases != (char **) NULL) >+ { >+ for (name = hp->h_aliases; >+ *name != (char *) NULL; >+ name++) >+ { >+ if (strcmp (client_ent->hostname, >+ *name) != 0) >+ { >+ (*aliascnt)++; >+ strcpy (ptr, *name); >+ ptr += strlen (ptr) + 1; >+ >+ /* Indicate just an alias */ >+ *ptr++ = 1; >+ } >+ } >+ } >+ >+ /* Pass official name last */ >+ if (strcmp (client_ent->hostname, hp->h_name) != 0) >+ { >+ (*aliascnt)++; >+ strcpy (ptr, hp->h_name); >+ ptr += strlen (ptr) + 1; >+ *ptr++ = 0; /* Indicate official name */ >+ } >+ >+ if (hp->h_addr_list != (char **) NULL) >+ { >+ addrlist = (struct in_addr **) hp->h_addr_list; >+ while (*addrlist) >+ { >+ memcpy (ptr, *(char **) addrlist, >+ sizeof (struct in_addr)); >+ ptr += sizeof (struct in_addr); >+ addrlist++; >+ } >+ } >+ memset (ptr, '\0', sizeof (struct in_addr)); >+ } >+ else /* Extra check for brain-dead gethostbyname() calls */ >+ { >+ if (client_ent->type == CE_NUMERIC) >+ { >+ struct in_addr temp; >+ >+ temp.s_addr = ntohl(inet_addr (client_ent->hostname)); >+ memcpy (ptr, (char *) &temp, >+ sizeof (struct in_addr)); >+ ptr += sizeof (struct in_addr); >+ memset (ptr, '\0', sizeof (struct in_addr)); >+ } >+ else >+ { >+ memset (ptr, '\0', sizeof (struct in_addr)); >+ /* Pass error code in packet */ >+ *(ptr + sizeof (struct in_addr) - 1) = h_errno; >+ } >+ } >+ >+ len = ptr - send_buffer + sizeof (struct in_addr); >+ notify_count++; >+ >+ dprintf (2, (LOG_DAEMON, LOG_DEBUG, >+ "%s: Sendto call number (%d) for client '%s'", >+ func, notify_count, client_ent->hostname)); >+ >+ if (notify_count % DNS_SLEEP == 0) >+ { >+ sleep (1); >+ } >+ >+ /* Send it to main process */ >+ sendto (rad_ipc_aatv->sockfd, send_buffer, len, (int) 0, >+ (struct sockaddr *) & send_sin, sizeof (send_sin)); >+ >+ } >+ >+ if (spawn_flag > 0) >+ { >+ _exit (0); >+ } >+ >+ return 0; >+} /* end of update_clients () */ >+ >+/************************************************************************* >+ * >+ * Function: user_find >+ * >+ * Purpose: Find the named user in the users database. Create the >+ * set of attribute-value pairs to check and reply with >+ * for this user from the database. >+ * >+ * Note that the users database can be either in the file >+ * "RADIUS_USERS" (-u option), in memory (default), or in >+ * a dbm(3) database. >+ * >+ *************************************************************************/ >+ >+int >+user_find (file_pfx, name, protocol, check_pairs, reply_pairs, not_user_file) >+ >+char *file_pfx; /* Selects which "users" file to use */ >+char *name; >+int protocol; >+VALUE_PAIR **check_pairs; >+VALUE_PAIR **reply_pairs; >+int not_user_file; /* Look up user in a domain specific file */ >+ >+{ >+ int mode; >+ int namelen; >+ FILE *userfd; >+ VALUE_PAIR *check_first; >+ VALUE_PAIR *reply_first; >+ VALUE_PAIR *prot_ent; >+ FILE_LIST *file_ent; >+ USER_ENTRY *user_ent; >+ USER_ENTRY *dflt_ent; >+ char *ptr; >+ FILE *debugout = stdout; >+ char buffer[256]; >+ char fname[MAXPATHLEN]; >+ static char *func = "user_find"; >+ >+#ifdef USE_NDBM >+ datum named; >+ datum contentd; >+ DBM *db; >+#endif /* USE_NDBM */ >+ >+#ifdef USE_DBM >+ datum named; >+ datum contentd; >+#endif /* USE_DBM */ >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered name='%s'", func, name)); >+ >+ *check_pairs = check_first = (VALUE_PAIR *) NULL; >+ *reply_pairs = reply_first = (VALUE_PAIR *) NULL; >+ >+ if ((namelen = strlen (name)) == 0) >+ { >+ return 1; /* A null name would match every line. */ >+ } >+ >+ /* >+ * First check what type of lookup to do. >+ * See if user file(s) have been cached in memory. >+ */ >+ >+ if (not_user_file == 0 && >+ (dflt_ent = file_list->user_list) != (USER_ENTRY *) NULL) >+ { >+ if ((file_ent = find_file_ent (file_pfx)) == (FILE_LIST *) NULL) >+ { >+ return (-1); >+ } >+ if ((user_ent = file_ent->user_list) == (USER_ENTRY *) NULL) >+ { >+ /* If no user file for this prefix, ... */ >+ /* ... then use first entry in file_list as ... */ >+ /* ... default file_ent. */ >+ user_ent = dflt_ent; >+ } >+ for (; user_ent; user_ent = user_ent->next) >+ { >+ /* Allow match for entry specifying framed protocol >+ * type specified in "protocol". An entry with a >+ * matching name but no framed-protocol type check >+ * item matches unconditionally. An entry with a >+ * matching name and a framed-protocol type check >+ * item must match value in "protocol". >+ */ >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: cache name='%s'", func, user_ent->name)); >+ >+#ifndef REGNAMES >+ if (strcmp (user_ent->name, name) == 0) >+#else /* REGNAMES */ >+ if (regimatch(user_ent->name, name)) >+#endif /* REGNAMES */ >+ { >+ if ((prot_ent = >+ get_vp (user_ent->check, >+ PW_FRAMED_PROTOCOL)) >+ == (VALUE_PAIR *) NULL) >+ { >+ break; >+ } >+ if (prot_ent->lvalue == protocol) >+ { >+ break; >+ } >+ } >+ } >+ if (!user_ent) /* rc 1 => User not found and no error */ >+ { >+ return 1; >+ } >+ list_copy (&check_first, user_ent->check); >+ list_copy (&reply_first, user_ent->reply); >+ if (debug_flag >= 2) >+ { >+ if (ddt) >+ { >+ debugout = ddt; >+ } >+ >+ fprintf (debugout, "Check items:\n"); >+ debug_list (debugout, user_ent->check); >+ fprintf (debugout, "Reply items:\n"); >+ debug_list (debugout, user_ent->reply); >+ } >+ *check_pairs = check_first; >+ *reply_pairs = reply_first; >+ return (0); /* rc 0 => User found */ >+ } /* End of cached users file(s) lookup */ >+ >+ /* >+ * Open the user table. >+ * If prefixed file doesn't exist, use default (non-prefixed) file. >+ */ >+ for (;;) >+ { >+ sprintf (fname, "%s/%s%s", radius_dir, >+ file_pfx ? file_pfx : "", RADIUS_USERS); >+ >+#if defined(USE_DBM) || defined(USE_NDBM) >+#ifdef USE_NDBM >+ if ((db = dbm_open (fname, O_RDONLY, 0)) == 0) >+ { >+#endif /* USE_NDBM */ >+#ifdef USE_DBM >+ if (dbminit (fname) != 0) >+ { >+#endif /* USE_DBM */ >+#else /* USE_DBM || USE_NDBM */ >+ if ((userfd = fopen (fname, "r")) == (FILE *) NULL) >+ { >+#endif /* USE_DBM || USE_NDBM */ >+ >+ if (not_user_file == 0 && >+ file_pfx != NULL && >+ file_pfx[0] != 0) >+ { >+ file_pfx = NULL; >+ continue; >+ } >+ >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Couldn't open %s for reading", >+ func, fname); >+ return (-1); >+ } >+ break; >+ } >+ >+#if defined(USE_DBM) || defined(USE_NDBM) >+/* >+ * Note that the DBM feature currently does not support protocol specific user >+ * entry matching. It could be done by appending a protocol type to the >+ * name when building the database and looking for that modified name here. >+ * This seems like a non-trivial task and we don't use the DBM feature >+ * here so I'll leave this to someone else to implement. >+ */ >+ named.dptr = name; >+ named.dsize = namelen; >+ >+#ifdef USE_NDBM >+ contentd = dbm_fetch (db, named); >+#else /* USE_NDBM */ >+ contentd = fetch (named); >+#endif /* USE_NDBM */ >+ >+ if (contentd.dsize == 0) >+ { >+ named.dptr = "DEFAULT"; >+ named.dsize = strlen ("DEFAULT"); >+ >+#ifdef USE_NDBM >+ contentd = dbm_fetch (db, named); >+#else /* USE_NDBM */ >+ contentd = fetch (named); >+#endif /* USE_NDBM */ >+ >+ if (contentd.dsize == 0) >+ { >+#ifdef USE_NDBM >+ dbm_close (db); >+#else /* USE_NDBM */ >+ dbmclose (); >+#endif /* USE_NDBM */ >+ return (-1); >+ } >+ } >+ >+ /* >+ * Parse the check values >+ */ >+ ptr = contentd.dptr; >+ contentd.dptr[contentd.dsize] = '\0'; >+ >+ if (pair_parse (ptr, &check_first) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Parse error for user %s in %s (check)", >+ func, name, fname); >+ list_free (check_first); >+#ifdef USE_NDBM >+ dbm_close (db); >+#else /* USE_NDBM */ >+ dbmclose (); >+#endif /* USE_NDBM */ >+ return (-1); >+ } >+ while (*ptr != '\n' && *ptr != '\0') >+ { >+ ptr++; >+ } >+ if (*ptr != '\n') >+ { >+ list_free (check_first); >+#ifdef USE_NDBM >+ dbm_close (db); >+#else /* USE_NDBM */ >+ dbmclose (); >+#endif /* USE_NDBM */ >+ return (-1); >+ } >+ ptr++; >+ >+ /* >+ * Parse the reply values >+ */ >+ if (pair_parse (ptr, &reply_first) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Parse error for user %s in %s (reply)", >+ func, name, fname); >+ list_free (check_first); >+ list_free (reply_first); >+#ifdef USE_NDBM >+ dbm_close (db); >+#else /* USE_NDBM */ >+ dbmclose (); >+#endif /* USE_NDBM */ >+ return (-1); >+ } >+#ifdef USE_NDBM >+ dbm_close (db); >+#else /* USE_NDBM */ >+ dbmclose (); >+#endif /* USE_NDBM */ >+ *check_pairs = check_first; >+ *reply_pairs = reply_first; >+ return (0); >+ >+#else /* USE_DBM || USE_NBDM */ >+ >+ mode = FIND_MODE_NAME; >+ >+ while (fgets (buffer, sizeof (buffer), userfd) != (char *) NULL) >+ { >+ if (*buffer == COMMENT) >+ { >+ continue; >+ } >+ >+ if (mode == FIND_MODE_NAME) >+ { >+ /* >+ * Find the entry starting with the users name. >+ */ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: name='%s'", func, user_ent->name)); >+ >+#ifndef REGNAMES >+ if (strncmp (buffer, name, namelen) == 0 && >+ (buffer[namelen] == ' ' || buffer[namelen] == '\t')) >+ { >+ ptr = &buffer[namelen]; >+#else /* REGNAMES */ >+ ptr = strtok(buffer, " \t\n"); >+ fprintf(debugout, "name='%s'", ptr); >+ if (regimatch(ptr, name)) >+ { >+ ptr = &buffer[strlen(ptr)+1]; >+ fprintf(debugout, "name='%s'", ptr); >+#endif /* REGNAMES */ >+ /* >+ * Parse the check values >+ */ >+ if (pair_parse (ptr, &check_first) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Parse error for user %s in %s (DBM check)", >+ func, name, fname); >+ list_free (check_first); >+ fclose (userfd); >+ return (-1); >+ } >+ /* Allow match for entry specifying framed >+ * protocol type specified in "protocol". An >+ * entry with matching name but no >+ * framed-protocol type check item matches >+ * unconditionally. An entry with matching >+ * name and a framed-protocol type check item >+ * must match value in "protocol". >+ */ >+ if ((prot_ent = >+ get_vp (check_first, >+ PW_FRAMED_PROTOCOL)) >+ != (VALUE_PAIR *) NULL) >+ { >+ if (prot_ent->lvalue != protocol) >+ { >+ list_free (check_first); >+ continue; >+ } >+ } >+ mode = FIND_MODE_REPLY; >+ } >+ } >+ else >+ { >+ if (*buffer == ' ' || *buffer == '\t') >+ { >+ /* >+ * Parse the reply values >+ */ >+ if (pair_parse (buffer, &reply_first) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, >+ "%s: Parse error for user %s in %s (DBM reply)", >+ func, name, fname); >+ list_free (check_first); >+ list_free (reply_first); >+ fclose (userfd); >+ return (-1); >+ } >+ } >+ else /* We are done */ >+ { >+ break; >+ } >+ } >+ } >+ fclose (userfd); >+ >+ /* Update the callers pointers */ >+ if (mode == FIND_MODE_NAME) >+ { >+ return 1; /* No error and no match */ >+ } >+ *check_pairs = check_first; >+ *reply_pairs = reply_first; >+ return (0); >+#endif /* USE_DBM || USE_NBDM */ >+} /* end of user_find () */ >+ >+static char * months[] = >+ { >+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", >+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" >+ }; >+ >+/************************************************************************* >+ * >+ * Function: user_gettime >+ * >+ * Purpose: Turns printable string into correct tm struct entries. >+ * >+ *************************************************************************/ >+ >+void >+user_gettime (valstr, tm) >+ >+char *valstr; >+struct tm *tm; >+ >+{ >+ int i; >+ static char *func = "user_gettime"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ /* Get the month */ >+ for (i = 0; i < 12; i++) >+ { >+ if (strncmp (months[i], valstr, 3) == 0) >+ { >+ tm->tm_mon = i; >+ i = 13; >+ } >+ } >+ >+ /* Get the Day */ >+ tm->tm_mday = atoi (&valstr[4]); >+ >+ /* Now the year */ >+ tm->tm_year = atoi (&valstr[7]) - 1900; >+} /* end of user_gettime () */ >+ >+/************************************************************************* >+ * >+ * Function: user_update >+ * >+ * Purpose: Updates a user in the database. Replaces the original >+ * entry with the name, the list of check items, and the >+ * list of reply items which are supplied. >+ * >+ *************************************************************************/ >+ >+int >+user_update (name, user_check, user_reply) >+ >+char *name; >+VALUE_PAIR *user_check; >+VALUE_PAIR *user_reply; >+ >+{ >+ FILE *oldfd; >+ FILE *userfd; >+ char buffer[256]; >+ char buffer1[256]; >+ int namelen; >+ int mode; >+ static char *func = "user_update"; >+ >+ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); >+ >+ sprintf (buffer, "%s/%s", radius_dir, RADIUS_USERS); >+ sprintf (buffer1, "%s/%s", radius_dir, RADIUS_HOLD); >+ >+ /* Move the user table to a temporary location */ >+ if (rename (buffer, buffer1) != 0) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: Couldn't rename %s", >+ func, buffer); >+ return (-1); >+ } >+ >+ /* Open the old user file (using the temporary name */ >+ if ((oldfd = fopen (buffer1, "r")) == (FILE *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: Couldn't open %s for reading", >+ func, buffer1); >+ exit (-9); >+ } >+ >+ /* Open the new user file */ >+ if ((userfd = fopen (buffer, "w")) == (FILE *) NULL) >+ { >+ logit (LOG_DAEMON, LOG_ERR, "%s: Couldn't open %s for writing", >+ func, buffer); >+ exit (-9); >+ } >+ >+ mode = FIND_MODE_NAME; >+ namelen = strlen (name); >+ >+ /* Copy the old to the new, only recreating the changed user */ >+ while (fgets (buffer, sizeof (buffer), oldfd) != (char *) NULL) >+ { >+ if (mode == FIND_MODE_NAME) >+ { >+ if ((strncmp (buffer, name, namelen) == 0 && >+ (buffer[namelen] == ' ' || buffer[namelen] == '\t'))) >+ { >+ >+ /* Write our new information */ >+ fprintf (userfd, "%s\t", name); >+ while (user_check != (VALUE_PAIR *) NULL) >+ { >+ fprint_attr_val (userfd, user_check); >+ if (user_check->next != >+ (VALUE_PAIR *) NULL) >+ { >+ fprintf (userfd, ", "); >+ } >+ user_check = user_check->next; >+ } >+ fprintf (userfd, "\n\t"); >+ while (user_reply != (VALUE_PAIR *) NULL) >+ { >+ fprint_attr_val (userfd, user_reply); >+ if (user_reply->next != >+ (VALUE_PAIR *) NULL) >+ { >+ fprintf (userfd, ",\n\t"); >+ } >+ user_reply = user_reply->next; >+ } >+ fprintf (userfd, "\n"); >+ mode = FIND_MODE_SKIP; >+ } >+ else >+ { >+ fputs (buffer, userfd); >+ } >+ } >+ else if (mode == FIND_MODE_SKIP) >+ { >+ if (*buffer != ' ' && *buffer != '\t') >+ { >+ fputs (buffer, userfd); >+ mode = FIND_MODE_FLUSH; >+ } >+ } >+ else >+ { >+ fputs (buffer, userfd); >+ } >+ } >+ fclose (oldfd); >+ fclose (userfd); >+ return (0); >+} /* end of user_update () */ >diff -rPu pppd.old/rad_util.c pppd/rad_util.c >--- pppd.old/rad_util.c Thu Jan 1 03:00:00 1970 >+++ pppd/rad_util.c Wed May 22 17:54:30 1996 >@@ -0,0 +1,178 @@ >+/* >+ * >+ * 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. >+ * >+ * [C] The Regents of the University of Michigan and Merit Network, Inc. 1992, >+ * 1993, 1994, 1995, 1996 All Rights Reserved >+ * >+ * 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 and this permission notice appear in all >+ * copies of the software and derivative works or modified versions thereof, >+ * and that both the copyright notice and this permission and disclaimer >+ * notice appear in supporting documentation. >+ * >+ * 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. >+ * >+ * Public entry points in this file: >+ * >+ * get_ipaddr >+ * good_ipaddr >+ * list_free >+ * >+ */ >+ >+static char sccsid[] = >+ "@(#)util.c 1.1 Copyright 1992 Livingston Enterprises Inc"; >+ >+static char rcsid[] = "$Id: util.c,v 1.9 1996/05/21 15:16:01 web Exp $"; >+ >+#include <sys/types.h> >+#include <sys/socket.h> >+#include <sys/time.h> >+#include <netinet/in.h> >+#include <arpa/inet.h> >+ >+#include <stdio.h> >+#include <netdb.h> >+#include <ctype.h> >+#include <time.h> >+ >+#include "radius.h" >+ >+/************************************************************************* >+ * >+ * Function: get_ipaddr >+ * >+ * Purpose: Return an IP address in host long notation from a host >+ * name or address in dot notation. >+ * >+ *************************************************************************/ >+ >+UINT4 >+get_ipaddr (host) >+ >+char *host; >+ >+{ >+ struct hostent *hp; >+ >+ if (good_ipaddr (host) == 0) >+ { >+ return ntohl(inet_addr (host)); >+ } >+ else if ((hp = gethostbyname (host)) == (struct hostent *) NULL) >+ { >+ return ((UINT4) 0); >+ } >+ return ntohl((*(UINT4 *) hp->h_addr)); >+} /* end of get_ipaddr () */ >+ >+/************************************************************************* >+ * >+ * Function: good_ipaddr >+ * >+ * Purpose: Check for valid IP address in standard dot notation. >+ * >+ *************************************************************************/ >+ >+int >+good_ipaddr (addr) >+ >+char *addr; >+ >+{ >+ int dot_count; >+ int digit_count; >+ >+ if (addr == (char *) NULL) >+ { >+ return (-1); >+ } >+ >+ dot_count = 0; >+ digit_count = 0; >+ >+ while (*addr != '\0' && *addr != ' ') >+ { >+ if (*addr == '.') >+ { >+ dot_count++; >+ digit_count = 0; >+ } >+ else if (!isdigit (*addr)) >+ { >+ dot_count = 5; >+ } >+ else >+ { >+ digit_count++; >+ if (digit_count > 3) >+ { >+ dot_count = 5; >+ } >+ } >+ addr++; >+ } >+ if (dot_count != 3) >+ { >+ return (-1); >+ } >+ else >+ { >+ return (0); >+ } >+} /* end of good_ipaddr () */ >+ >+/************************************************************************* >+ * >+ * Function: list_free >+ * >+ * Purpose: Release the memory used by a list of a/v pairs. >+ * >+ *************************************************************************/ >+ >+void >+list_free (pair) >+ >+VALUE_PAIR *pair; >+ >+{ >+ VALUE_PAIR *next; >+ >+ while (pair != (VALUE_PAIR *) NULL) >+ { >+ next = pair->next; >+ free (pair); >+ pair = next; >+ } >+ return; >+} /* end of list_free () */ >diff -rPu pppd.old/radius.h pppd/radius.h >--- pppd.old/radius.h Thu Jan 1 03:00:00 1970 >+++ pppd/radius.h Sat Dec 11 13:40:57 1999 >@@ -0,0 +1,1137 @@ >+#ifndef RADIUS_H >+#define RADIUS_H >+ >+/* >+ * 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. >+ * >+ * [C] The Regents of the University of Michigan and Merit Network, Inc. 1992, >+ * 1993, 1994, 1995, 1996 All Rights Reserved >+ * >+ * 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 and this permission notice appear in all >+ * copies of the software and derivative works or modified versions thereof, >+ * and that both the copyright notice and this permission and disclaimer >+ * notice appear in supporting documentation. >+ * >+ * 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. >+ * >+ * @(#)radius.h 1.3 1/20/93 >+ * >+ * $Id: radius.h,v 2.64 1996/06/19 18:16:23 web Exp $ >+ */ >+ >+#include "conf.h" >+ >+#define COMMENT '#' /* comment char for config files */ >+ >+#define AUTH_VECTOR_LEN 16 >+#define AUTH_PASS_LEN 64 >+#define AUTH_ID_LEN 64 >+#define AUTH_STRING_LEN 128 /* maximum of 253 */ >+ >+#define FILTER_LEN 16 >+#define NAME_LENGTH 32 >+#define MAX_FSMID_LEN 20 /* Maximum length of %FSMID string */ >+ >+typedef struct pw_auth_hdr >+{ >+ u_char code; >+ u_char id; >+ u_short length; >+ u_char vector[AUTH_VECTOR_LEN]; >+ u_char data[2]; >+} AUTH_HDR; >+ >+#define AUTH_HDR_LEN 20 >+#define MAX_SECRET_LENGTH 16 >+#define CHAP_VALUE_LENGTH 16 >+ >+#if !defined(PW_AUTH_UDP_PORT) >+#define PW_AUTH_UDP_PORT 1645 >+#endif >+ >+#if !defined(PW_ACCT_UDP_PORT) >+#define PW_ACCT_UDP_PORT 1646 >+#endif >+ >+#define PW_TYPE_STRING 0 >+#define PW_TYPE_INTEGER 1 >+#define PW_TYPE_IPADDR 2 >+#define PW_TYPE_DATE 3 >+#define PW_TYPE_OCTETS 4 >+#define PW_TYPE_VENDOR 5 >+ >+/* standard RADIUS codes */ >+ >+#define PW_ACCESS_REQUEST 1 >+#define PW_ACCESS_ACCEPT 2 >+#define PW_ACCESS_REJECT 3 >+#define PW_ACCOUNTING_REQUEST 4 >+#define PW_ACCOUNTING_RESPONSE 5 >+#define PW_ACCOUNTING_STATUS 6 >+#define PW_PASSWORD_REQUEST 7 >+#define PW_PASSWORD_ACK 8 >+#define PW_PASSWORD_REJECT 9 >+#define PW_ACCOUNTING_MESSAGE 10 >+#define PW_ACCESS_CHALLENGE 11 >+#define PW_STATUS_SERVER 12 >+#define PW_STATUS_CLIENT 13 >+#define PW_FORWARDING 216 >+ >+ >+/* standard RADIUS attribute-value pairs */ >+ >+#define PW_USER_NAME 1 /* string */ >+#define PW_USER_PASSWORD 2 /* string */ >+#define PW_CHAP_PASSWORD 3 /* string */ >+#define PW_NAS_IP_ADDRESS 4 /* ipaddr */ >+#define PW_NAS_PORT 5 /* integer */ >+#define PW_SERVICE_TYPE 6 /* integer */ >+#define PW_FRAMED_PROTOCOL 7 /* integer */ >+#define PW_FRAMED_IP_ADDRESS 8 /* ipaddr */ >+#define PW_FRAMED_IP_NETMASK 9 /* ipaddr */ >+#define PW_FRAMED_ROUTING 10 /* integer */ >+#define PW_FILTER_ID 11 /* string */ >+#define PW_FRAMED_MTU 12 /* integer */ >+#define PW_FRAMED_COMPRESSION 13 /* integer */ >+#define PW_LOGIN_IP_HOST 14 /* ipaddr */ >+#define PW_LOGIN_SERVICE 15 /* integer */ >+#define PW_LOGIN_PORT 16 /* integer */ >+#define PW_OLD_PASSWORD 17 /* string */ /* deprecated */ >+#define PW_REPLY_MESSAGE 18 /* string */ >+#define PW_LOGIN_CALLBACK_NUMBER 19 /* string */ >+#define PW_FRAMED_CALLBACK_ID 20 /* string */ >+#define PW_EXPIRATION 21 /* date */ /* deprecated */ >+#define PW_FRAMED_ROUTE 22 /* string */ >+#define PW_FRAMED_IPX_NETWORK 23 /* integer */ >+#define PW_STATE 24 /* string */ >+#define PW_CLASS 25 /* string */ >+#define PW_VENDOR_SPECIFIC 26 /* string */ >+#define PW_SESSION_TIMEOUT 27 /* integer */ >+#define PW_IDLE_TIMEOUT 28 /* integer */ >+#define PW_TERMINATION_ACTION 29 /* integer */ >+#define PW_CALLED_STATION_ID 30 /* string */ >+#define PW_CALLING_STATION_ID 31 /* string */ >+#define PW_NAS_IDENTIFIER 32 /* string */ >+#define PW_PROXY_STATE 33 /* string */ >+#define PW_LOGIN_LAT_SERVICE 34 /* string */ >+#define PW_LOGIN_LAT_NODE 35 /* string */ >+#define PW_LOGIN_LAT_GROUP 36 /* string */ >+#define PW_FRAMED_APPLETALK_LINK 37 /* integer */ >+#define PW_FRAMED_APPLETALK_NETWORK 38 /* integer */ >+#define PW_FRAMED_APPLETALK_ZONE 39 /* string */ >+#define PW_CHAP_CHALLENGE 60 /* string */ >+#define PW_NAS_PORT_TYPE 61 /* integer */ >+#define PW_PORT_LIMIT 62 /* integer */ >+#define PW_LOGIN_LAT_PORT 63 /* string */ >+ >+/* Accounting */ >+ >+#define PW_ACCT_STATUS_TYPE 40 /* integer */ >+#define PW_ACCT_DELAY_TIME 41 /* integer */ >+#define PW_ACCT_INPUT_OCTETS 42 /* integer */ >+#define PW_ACCT_OUTPUT_OCTETS 43 /* integer */ >+#define PW_ACCT_SESSION_ID 44 /* string */ >+#define PW_ACCT_AUTHENTIC 45 /* integer */ >+#define PW_ACCT_SESSION_TIME 46 /* integer */ >+#define PW_ACCT_INPUT_PACKETS 47 /* integer */ >+#define PW_ACCT_OUTPUT_PACKETS 48 /* integer */ >+#define PW_ACCT_TERMINATE_CAUSE 49 /* integer */ >+#define PW_ACCT_MULTI_SESSION_ID 50 /* string */ >+ >+/* Merit Experimental Extensions */ >+ >+/* Temporary assignment for LOG AATV session logging */ >+ >+#define PW_LAS_START_TIME 145 /* integer */ >+#define PW_LAS_CODE 146 /* integer */ >+#define PW_LAS_DURATION 147 /* integer */ >+#define PW_LOCAL_DURATION 148 /* integer */ >+ >+#define PW_SERVICE_CLASS 149 /* string */ >+#define PW_PORT_ENTRY 150 /* string */ >+#define PW_PROXY_ACTION 211 /* string */ >+#define PW_TOKEN 213 /* string */ >+#define PW_HUNTGROUP_NAME 221 /* string */ >+#define PW_USER_ID 222 /* string */ >+#define PW_USER_REALM 223 /* string */ >+ >+/* Configuration Only Attributes (for check-items) */ >+ >+#define CI_COMMENT 1024 /* string */ >+#define CI_XVALUE 1025 /* integer */ >+#define CI_XSTRING 1026 /* string */ >+#define CI_AUTHENTICATION_TYPE 1027 /* integer */ >+#define CI_PROHIBIT 1028 /* integer */ >+#define CI_USER_CATEGORY 1029 /* string */ >+#define CI_GROUP_NAME 1030 /* string */ >+#define CI_ENCRYPTED_PASSWORD 1031 /* string */ >+#define CI_EXPIRATION 1032 /* date */ >+#define CI_USER_PASSWORD 1033 /* string */ >+#define CI_SIMULTANEOUS_USE 1034 /* integer */ >+#define CI_SERVER_NAME 1035 /* string */ >+ >+/* Integer Translations */ >+ >+/* SERVICE TYPES */ >+ >+#define PW_LOGIN 1 >+#define PW_FRAMED 2 >+#define PW_CALLBACK_LOGIN 3 >+#define PW_CALLBACK_FRAMED 4 >+#define PW_OUTBOUND_USER 5 >+#define PW_ADMINISTRATIVE_USER 6 >+#define PW_SHELL_USER 7 >+#define PW_AUTHENTICATE_ONLY 8 >+#define PW_CALLBACK_ADMIN_USER 9 >+ >+/* FRAMED PROTOCOLS */ >+ >+#define PW_PPP 1 >+#define PW_SLIP 2 >+#define PW_ARA 3 >+#define PW_GANDALF 4 >+ >+/* FRAMED ROUTING VALUES */ >+ >+#define PW_NONE 0 >+#define PW_BROADCAST 1 >+#define PW_LISTEN 2 >+#define PW_BROADCAST_LISTEN 3 >+ >+/* FRAMED COMPRESSION TYPES */ >+ >+#define PW_VAN_JACOBSON_TCP_IP 1 >+#define PW_IPX_HEADER_COMPRESSION 2 >+ >+/* LOGIN SERVICES */ >+ >+#define PW_TELNET 0 >+#define PW_RLOGIN 1 >+#define PW_TCP_CLEAR 2 >+#define PW_PORTMASTER 3 >+#define PW_LAT 4 >+ >+/* TERMINATION ACTIONS */ >+ >+#define PW_DEFAULT 0 >+#define PW_RADIUS_REQUEST 1 >+ >+/* AUTHENTICATION TYPES */ >+ >+#define AA_NONE 0 /* This is not a valid user id entry */ >+#define AA_UNIX 1 /* Use local Unix password file */ >+#define AA_AKRB 2 /* AFS Kerberos type authentication */ >+#define AA_MKRB 3 /* MIT Kerberos type authentication */ >+#define AA_RAD 4 /* Pass to remote RADIUS server */ >+#define AA_MNET 5 /* Do Merit specific authentication */ >+#define AA_KCHAP 6 /* Kerberos CHAP authentication */ >+#define AA_TACACS 7 /* Encrypted TACACS authentication */ >+#define AA_REALM 8 /* Find given realm in authfile */ >+#define AA_LOCAL 9 >+#define AA_FILE 10 /* ID/PW list in a file */ >+#define AA_SCRIPT 11 /* External script */ >+ >+#define PW_AUTH_MAX 11 /* Highest authentication type */ >+ >+/* PROHIBIT PROTOCOL */ >+ >+#define PW_DUMB 0 /* 1 and 2 are defined in FRAMED PROTOCOLS */ >+#define PW_AUTH_ONLY 3 >+#define PW_ALL 255 >+ >+/* ACCOUNTING STATUS TYPES */ >+ >+#define PW_STATUS_START 1 >+#define PW_STATUS_STOP 2 >+#define PW_STATUS_ALIVE 3 >+#define PW_STATUS_MODEM_START 4 >+#define PW_STATUS_MODEM_STOP 5 >+#define PW_STATUS_CANCEL 6 >+#define PW_ACCOUNTING_ON 7 >+#define PW_ACCOUNTING_OFF 8 >+ >+/* ACCOUNTING TERMINATION CAUSES */ >+ >+#define PW_USER_REQUEST 1 >+#define PW_LOST_CARRIER 2 >+#define PW_LOST_SERVICE 3 >+#define PW_ACCT_IDLE_TIMEOUT 4 >+#define PW_ACCT_SESSION_TIMEOUT 5 >+#define PW_ADMIN_RESET 6 >+#define PW_ADMIN_REBOOT 7 >+#define PW_PORT_ERROR 8 >+#define PW_NAS_ERROR 9 >+#define PW_NAS_REQUEST 10 >+#define PW_NAS_REBOOT 11 >+#define PW_PORT_UNNEEDED 12 >+#define PW_PORT_PREEMPTED 13 >+#define PW_PORT_SUSPENDED 14 >+#define PW_SERVICE_UNAVAILABLE 15 >+#define PW_CALLBACK 16 >+#define PW_USER_ERROR 17 >+#define PW_HOST_REQUEST 18 >+ >+/* NAS PORT TYPES */ >+ >+#define PW_ASYNC 0 >+#define PW_SYNC 1 >+#define PW_ISDN_SYNC 2 >+#define PW_ISDN_SYNC_V120 3 >+#define PW_ISDN_SYNC_V110 4 >+ >+/* Default Database File Names */ >+ >+#ifndef RADIUS_DIR >+#define RADIUS_DIR "/var/adm/raddb" >+#endif >+ >+#ifndef RADACCT_DIR >+#define RADACCT_DIR "/var/adm/radacct" >+#endif >+ >+#ifndef RADIUS_SCRIPT >+#define RADIUS_SCRIPT "/usr/local/adm/radauth" >+#endif >+ >+#ifndef RADIUS_SCRIPT_ACCT >+#define RADIUS_SCRIPT_ACCT "/usr/local/adm/radacct" >+#endif >+ >+/* >+ * Note: To change where these files go, do not change the #defines >+ * below, instead change the RADIUS_DIR #define above. >+ */ >+ >+#define RADIUS_DICTIONARY "dictionary" >+#define RADIUS_CLIENTS "clients" >+#define RADIUS_USERS "users" >+#define RADIUS_HOLD "holdusers" >+#define RADIUS_LOG "/var/adm/radius.log" >+#define RADIUS_AUTH "authfile" >+#define RADIUS_PID "radiusd.pid" >+#define RADIUS_FSM "radius.fsm" >+#define RADIUS_DEBUG "/tmp/radius.debug" >+ >+#ifndef RADIUS_COMPRESS >+#define RADIUS_COMPRESS "/usr/bin/gzip" /* might be gzip, etc. */ >+#endif >+ >+#ifndef RADIUS_LOCALSERVER >+#define RADIUS_LOCALSERVER "localserver" >+#endif >+ >+#ifndef DEFAULT_REALM >+#define DEFAULT_REALM "DEFAULT" >+#endif >+ >+#ifndef NULL_REALM >+#define NULL_REALM "NULL" >+#endif >+ >+/* Server data structures */ >+ >+typedef struct dict_attr >+{ >+ char name[NAME_LENGTH + 1]; /* attribute name */ >+ int value; /* attribute index */ >+ int type; /* string, int, etc. */ >+ struct dict_attr *next; >+} DICT_ATTR; >+ >+typedef struct dict_value >+{ >+ char attrname[NAME_LENGTH +1]; >+ char name[NAME_LENGTH + 1]; >+ int value; >+ struct dict_value *next; >+} DICT_VALUE; >+ >+typedef struct value_pair >+{ >+ char name[NAME_LENGTH + 1]; >+ int attribute; >+ int type; >+ UINT4 lvalue; >+ char strvalue[AUTH_STRING_LEN + 1]; >+ struct value_pair *next; >+} VALUE_PAIR; >+ >+typedef struct auth_req >+{ >+ UINT4 ipaddr; /* IP address of requestor */ >+ u_short udp_port; /* UDP reply socket of requestor */ >+ u_char id; /* Original request seq. number */ >+ u_char code; /* Type of RADIUS packet */ >+ u_char vector[AUTH_VECTOR_LEN]; >+ char *secret; >+ char *file_pfx; >+ char *realm_filter; >+ u_char ttl; /* Global queue time-to-live secs */ >+ u_char timer; /* General utility timer */ >+ u_char reply_id; /* RADIUS-to-RADIUS seq. number */ >+ u_char retry_cnt; /* Counter for duplicate requests */ >+ u_char state; /* State of current request */ >+ u_char sws; /* Switches, flags, etc. */ >+ int result; /* Result of previous action */ >+ int cur_count; /* Original number request pairs */ >+ struct aatv *fsm_aatv; /* Pointer to current FSM action */ >+ struct aatv *direct_aatv; /* Pointer to actual action */ >+ struct event_ent *event_q; /* Pointer to active event queue */ >+ struct auth_req *next; /* Global request queue link */ >+ VALUE_PAIR *request; /* Original client a/v pairs */ >+ VALUE_PAIR *cur_request; /* Represents current a/v pairs */ >+ VALUE_PAIR *user_check; /* List of users file check items */ >+} AUTH_REQ; >+ >+typedef struct event_ent >+{ >+ struct event_ent *next; >+ AUTH_REQ *auth_head; /* pointer back to the authreq structure */ >+ struct aatv *fsm_aatv; /* record action from FSM table */ >+ struct aatv *sub_aatv; /* record action when request was issued */ >+ u_char *packet; /* copy of request packet which was sent */ >+ int len; /* length of packet */ >+ pid_t pid; /* fork type: pid, socket type: == zero */ >+ struct sockaddr_in sin; /* socket info for packet re-sending */ >+ int evalue; /* AATV act_func integer argument */ >+ u_char state; /* state in which the request was issued */ >+ char action[NAME_LENGTH+1]; /* "cmd" arg to radius_send */ >+ char estring[AUTH_ID_LEN]; /* AATV act_func string arg */ >+} EVENT_ENT; >+ >+typedef struct user_ent >+{ >+ struct user_ent *next; >+ char *name; >+ VALUE_PAIR *check; >+ VALUE_PAIR *reply; >+} USER_ENTRY; >+ >+#ifdef MERIT_LAS >+typedef struct lasrealm_ent *LAS_REALM; >+#endif /* MERIT_LAS */ >+ >+typedef struct auth_ent >+{ >+ struct auth_ent *next; >+ char *name; >+ struct auth_ent *parent; >+ int prot; >+ int type; >+ char *host; >+ char *filter; >+#ifdef MERIT_LAS >+ LAS_REALM las_realm; >+#endif /* MERIT_LAS */ >+} AUTH_ENTRY; >+ >+/* The following must match the beginning of the auth_ent structure */ >+typedef struct auth_aent >+{ >+ struct auth_ent *next; >+ char *name; >+ struct auth_ent *parent; >+} AUTH_ALIAS_ENTRY; >+ >+typedef struct linklist_entry >+{ >+ struct linklist_entry *next; /* pointer to next entry in list */ >+} LINKLIST_ENT; >+ >+#define numbof(X) (sizeof(X)/sizeof(X[0])) >+ >+typedef struct name_list >+{ >+ struct name_list *next; >+ char *name; >+ u_char flag; >+ u_short num; >+} NAME_LIST; >+ >+/* Binary port entry structure used in Port-Entry attribute */ >+ >+#define PORT_ENTRY_VERSION 0 /* increase if change structure here */ >+ >+typedef struct bin_port_ent >+{ >+ u_char version; /* be sure to use PORT_ENTRY_VERSION */ >+ u_char port_source; /* zero => was HGAS, one => otherwise */ >+ time_t start_time; /* start time of session on this port */ >+ UINT4 port_nbr; /* port number of this session */ >+ UINT4 duration; /* session length (seconds) */ >+} BIN_PORT_ENT; >+ >+/* >+ * Use the following to specify default "realm" names to use for >+ * authentication-type entries of RADIUS or TACACS that may be >+ * configured in the "users" file. May be configured globally >+ * in the Makefile or changed in the authfile on a running server. >+ */ >+ >+#ifndef DEFAULT_RADIUS_SERVER >+#define DEFAULT_RADIUS_SERVER "" >+#endif >+ >+#ifndef DEFAULT_TACACS_SERVER >+#define DEFAULT_TACACS_SERVER "" >+#endif >+ >+/****************************************************************** >+ * >+ * PW_PROTTYPE & PW_PROTTYPES - define authentication protocol allowed >+ * for particular realm entry in authfile. >+ * >+ * The PW_PROTTYPE value is stored in the auth_ent.prot field. >+ * The PW_PROTTYPE value corresponds to the order of PW_PROTTYPES. >+ * >+ *****************************************************************/ >+ >+#define PW_PROTTYPE_DFLT 0 /* Use this entry for any protocol */ >+#define PW_PROTTYPE_CHAP 1 /* Entry is for CHAP style authent. */ >+#define PW_PROTTYPE_PW 2 /* Entry is for id/pw style authent. */ >+ >+#define PW_PROTTYPES_DFLT "DEFAULT" >+#define PW_PROTTYPES_CHAP "CHAP" >+#define PW_PROTTYPES_PW "PW" >+ >+typedef struct file_list >+{ >+ struct file_list *next; >+ char *prefix; >+ USER_ENTRY *user_list; >+ AUTH_ENTRY *auth_list; >+} FILE_LIST; >+ >+typedef struct ip_address >+{ >+ struct ip_address *next; >+ struct in_addr ipaddr; >+} IP_ADDRESS; >+ >+typedef struct dns_name >+{ >+ struct dns_name *next; >+ u_char type; /* 0 = official name, 1 = alias */ >+ char name[1]; >+} DNS_NAME; >+ >+typedef struct client_ent >+{ >+ struct client_ent *next; >+ IP_ADDRESS *addrs; >+ char *secret; >+ char *prefix; >+ char *hostname; >+ DNS_NAME *names; >+ time_t expire_time; >+ enum {CE_DNS, CE_NUMERIC, CE_OURADDR} type; >+} CLIENT_ENTRY; >+ >+#define dprintf(lev, args) { if (debug_flag >= lev) logit args; } >+#define ddumpx(lev, args) { if (debug_flag > lev) dumpit args; } >+ >+/* Define return codes from "SendServer" utility */ >+ >+#define BADRESP_RC -2 >+#define ERROR_RC -1 >+#define OK_RC 0 >+#define TIMEOUT_RC 1 >+ >+typedef struct send_data /* Used to pass information to sendserver() function */ >+{ >+ u_char code; /* RADIUS packet code */ >+ u_char seq_nbr; /* Packet sequence number */ >+ char *user_name; >+ char *password; /* Cleartext user password */ >+ u_char ustype; /* Service-Type attribute */ >+ u_char fptype; /* Framed-Protocol attribute */ >+ char *server; /* Name/addrress of RADIUS server */ >+ int svc_port; /* RADIUS protocol destination port */ >+ int timeout; /* Session timeout in seconds */ >+ UINT4 client_id; /* IP address of client */ >+ int port_num; /* Port number on client */ >+ char *user_file; /* Users style file of a/v pairs */ >+ char *group; >+ VALUE_PAIR *send_pairs; /* More a/v pairs to send */ >+ VALUE_PAIR **receive_pairs; /* Where to place received a/v pairs */ >+} SEND_DATA; >+ >+/* >+ * Handle older syslog versions, too! >+ */ >+ >+#ifndef LOG_CONS >+#define LOG_DAEMON 0 >+#define LOG_AUTH 0 >+#endif >+ >+#define MGMT_POLL_SECRET "Hardlyasecret" >+#define MAX_REQUESTS 128 >+#define MAX_REQUEST_TIME 30 /* Lifetime of a request */ >+#define CLEANUP_DELAY 5 /* Hold onto old requests this long */ >+#define DEFAULT_INETD_TIMEOUT 15 /* Fifteen minutes by default */ >+#define DEFAULT_TIMER_VALUE 3 /* Three seconds by default */ >+#define ADDRESS_AGING 60*60 /* One hour by default */ >+#define DFLT_TACACS_UDP_PORT 49 /* Default TACACS server port */ >+#define SESS_ID_LEN 8 /* session id length */ >+#define SECONDS_PER_DAY 86400 >+#define TRUNCATION_DAY 7 /* Sunday is zero (0), daily is seven (7) */ >+#define DNS_SLEEP 100 /* Time which DNS sub-process sleeps. */ >+ >+typedef enum /* error code */ >+{ >+ EC_OK, /* no error */ >+ EC_INTERNAL, /* internal error */ >+ EC_CONFIG, /* configuration error */ >+ EC_NO_MEMORY, /* out of memory */ >+ EC_CREATE_FILE, /* error creating file */ >+ EC_NO_TOKEN, /* no token available */ >+ EC_NO_PORTS, /* no ports available for guests */ >+ EC_TOO_MANY_SESSIONS, /* user has too many sessions */ >+ EC_ABS_FAILURE, /* ABS failed (with message) */ >+ EC_NO_BALANCE, /* error querying for balance */ >+ EC_BAD_BALANCE /* balance too low */ >+} ERRORCODE; >+ >+typedef enum /* accounting code */ >+{ >+ AC_ERROR = -1, /* no accounting code */ >+ AC_NORMAL, /* normal disconnect */ >+ AC_REJECT, /* rejected by this server */ >+ AC_CANCEL, /* access rejected by someone */ >+ AC_NOCONFIRM, /* no confirmation */ >+ AC_OVERTIME, /* session over maximum time allowed */ >+ AC_UNKNOWN, /* session ended for unknown reason */ >+ AC_NOTOKEN, /* rejected because no token */ >+ AC_NOTLOCAL, /* session not local */ >+ AC_SUSPEND, /* session suspended */ >+ AC_FAILED, /* authentication failed */ >+ AC_AUTHORIZED, /* session authorized (for stats) */ >+ AC_NASREBOOT, /* released due to NAS reboot */ >+ AC_REMOTE, /* remote session, failed to forward */ >+ AC_NUMBOFCODE /* number of accounting code */ >+} ACCTCODE; >+ >+#ifndef PROTO >+#ifdef __STDC__ >+#define PROTO(x) x >+#else >+#define PROTO(x) () >+#define const >+#endif /* !__STDC__ */ >+#endif /* !PROTO */ >+ >+union action_u >+{ >+ struct aatv *aatv; /* points to the id field of an AATV */ >+ char *proxy; /* pointer to a Proxy-Action string */ >+} UACTION; >+ >+/* Define event structure (for events generated by AATV recv functions */ >+ >+typedef struct ev >+{ >+ u_char state; >+ union action_u a; >+ int isproxy; /* set to one if action "a" is proxy */ >+ int value; >+ char xstring[AUTH_ID_LEN]; >+} EV; >+ >+/* Define aatvfunc_type codes */ >+ >+#define AA_DIRECT 0 /* Function gives direct reply */ >+#define AA_SOCKET 1 /* Deferred reply returned on socket */ >+#define AA_FORK 2 /* Spawn a process to wait for reply */ >+#define AA_FREPLY 3 /* Fork & get reply on server socket */ >+ >+typedef struct aatv >+{ >+ u_char id[NAME_LENGTH + 1]; >+ char authen_type; /* a -1 value indicates built-in AATV types */ >+ u_char aatvfunc_type; >+ void (*init) PROTO((struct aatv *)); >+ int (*timer) PROTO((void)); >+ int (*act_func) PROTO((AUTH_REQ *, int, char *)); >+ AUTH_REQ * (*recv) PROTO((struct sockaddr_in *, UINT4, u_int, EV *)); >+ void (*cleanup) PROTO((void)); >+ UINT4 sockfd; >+} AATV, *AATVPTR; >+ >+extern AATV *authtype_tv[]; >+ >+#ifdef MERIT_LAS >+extern AATVPTR rad_log_aatv; /* For logging (selector) */ >+extern AATVPTR rad_log_all_aatv; /* For logging (debugging) */ >+extern AATVPTR rad_log_brief_aatv; /* For logging (logging) */ >+extern AATVPTR rad_log_old_aatv; /* For logging (logging) */ >+extern AATVPTR rad_log_v1_0_aatv; /* For logging (logging) */ >+extern AATVPTR rad_log_v1_1_aatv; /* For logging (logging) */ >+extern AATVPTR rad_log_v2_0_aatv; /* For logging (logging) */ >+extern AATVPTR rad_log_v2_1_aatv; /* For logging (logging) */ >+#endif /* MERIT_LAS */ >+ >+/* Specify all authentication/authorization transfer vectors here. */ >+ >+extern AATVPTR rad_realm_aatv; /* Needed for authtype = realm */ >+extern AATVPTR rad_2rad_aatv; /* Authtype = Radius */ >+extern AATVPTR rad_tacs_aatv; /* Authtype = TACACS */ >+extern AATVPTR rad_unix_aatv; /* Authtype = Unix-pw */ >+extern AATVPTR rad_kchp_aatv; /* Authtype = KCHAP */ >+extern AATVPTR rad_mnet_aatv; /* Authtype = mnet */ >+extern AATVPTR rad_akrb_aatv; /* Authtype = akerb */ >+extern AATVPTR rad_mkrb_aatv; /* Authtype = mkerb */ >+extern AATVPTR rad_script_aatv; /* Authtype = SCRIPT */ >+extern AATVPTR rad_file_aatv; /* Authtype = File */ >+extern AATVPTR rad_authen_aatv; /* Authentication begins here */ >+extern AATVPTR rad_passwd_aatv; /* Used for changing passwords */ >+ >+#ifdef MERIT_HUNTGROUP >+#include "huntgroup.h" >+#define EN_HGAS1 "HGAS1" >+#define EN_HGAS2 "HGAS2" >+#define EN_HGAS3 "HGAS3" >+#define EN_HGAS4 "HGAS4" >+#define EN_BACCT "BACCT" >+extern AATVPTR rad_hgas1_aatv; /* Hg Authorization begins here */ >+extern AATVPTR rad_hgas2_aatv; /* Hg Authorization continues here */ >+extern AATVPTR rad_hgas3_aatv; /* Hg Accounting begins here */ >+extern AATVPTR rad_hgas4_aatv; /* Hg Accounting continues here */ >+extern AATVPTR rad_hgasrmt_aatv; /* Hg forwarding to remote server */ >+extern AATVPTR rad_hgacctrmt_aatv; /* Hg accounting origination */ >+extern AATVPTR rad_hgaslog_aatv; /* Hg logging action (for HGAS1) */ >+ >+#ifdef MERIT_HUNTGROUP_DAC >+extern AATVPTR rad_hgdac1_aatv; /* Hg DAC policy begins here */ >+extern AATVPTR rad_hgdac2_aatv; /* Hg DAC policy continues here */ >+extern AATVPTR rad_hgdac3_aatv; /* Hg DAC accounting begins here */ >+#define DACAATVS ,&rad_hgdac1_aatv,&rad_hgdac2_aatv,&rad_hgdac3_aatv >+#else /* MERIT_HUNTGROUP_DAC */ >+#define DACAATVS >+#endif /* MERIT_HUNTGROUP_DAC */ >+ >+#ifdef MERIT_HUNTGROUP_SHP >+extern AATVPTR rad_hgshp1_aatv; /* Hg SHP policy begins here */ >+extern AATVPTR rad_hgshp2_aatv; /* Hg SHP policy continues here */ >+extern AATVPTR rad_hgshp3_aatv; /* Hg SHP accounting begins here */ >+#define SHPAATVS ,&rad_hgshp1_aatv,&rad_hgshp2_aatv,&rad_hgshp3_aatv >+#else /* MERIT_HUNTGROUP_SHP */ >+#define SHPAATVS >+#endif /* MERIT_HUNTGROUP_SHP */ >+ >+#define HGAATVS ,&rad_hgas1_aatv,&rad_hgas2_aatv,&rad_hgas3_aatv,&rad_hgas4_aatv,&rad_hgasrmt_aatv,&rad_hgaslog_aatv,&rad_hgacctrmt_aatv DACAATVS SHPAATVS >+#else /* MERIT_HUNTGROUP */ >+#define HGAATVS >+#define EN_HGAS1 "" >+#define EN_HGAS2 "" >+#define EN_HGAS3 "" >+#define EN_HGAS4 "" >+#define EN_BACCT "" >+#endif /* MERIT_HUNTGROUP */ >+ >+#ifdef MERIT_ORGANIZATION >+#include "oas.h" >+#define EN_OAS "OAS" >+#define EN_OAS_ACCT "OAS_ACCT" >+extern AATVPTR rad_oas_aatv; /* Org Authorization begins here */ >+extern AATVPTR rad_oasrem_aatv; /* Org Authorization remote stuff */ >+extern AATVPTR rad_oasloc_aatv; /* Org Authorization local stuff */ >+extern AATVPTR oas_acct_aatv; /* Org Accounting begins here */ >+#define OASAATVS ,&rad_oas_aatv,&rad_oasrem_aatv,&rad_oasloc_aatv,&oas_acct_aatv >+#else /* MERIT_ORGANIZATION */ >+#define OASAATVS >+#define EN_OAS "" >+#define EN_OAS_ACCT "" >+#endif /* MERIT_ORGANIZATION */ >+ >+#ifdef MERIT_LAS >+#include "las.h" >+#define EN_LAS "AUTHENTICATE" >+#define EN_LAS_ACCT "LAS_ACCT" >+extern AATVPTR rad_las_aatv; /* Local authorization */ >+extern AATVPTR las_auth_subaatv; /* Generic LAS authorization */ >+extern AATVPTR las_acct_subaatv; /* Generic LAS accounting */ >+extern AATVPTR las_acct_aatv; /* LAS accounting */ >+ >+#ifdef LAS_NO_HGAS >+#define LASCPAATV >+#else /* LAS_NO_HGAS */ >+extern AATVPTR lascp_aatv; /* LAS synchronizing */ >+#define LASCPAATV ,&lascp_aatv >+#endif /* LAS_NO_HGAS */ >+ >+#ifdef UOFM_LAS >+#include "umlas.h" >+extern AATVPTR las_um_aatv; /* U of M LAS */ >+#define LASAATVS ,&las_auth_subaatv,&las_acct_subaatv,&las_um_aatv, \ >+ &rad_las_aatv,&las_acct_aatv LASCPAATV >+#else /* UOFM_LAS */ >+#define LASAATVS ,&las_auth_subaatv,&las_acct_subaatv, \ >+ &rad_las_aatv,&las_acct_aatv LASCPAATV >+#endif /* UOFM_LAS */ >+#else /* MERIT_LAS */ >+#define LASAATVS >+#define EN_LAS "" >+#define EN_LAS_ACCT "" >+#endif /* MERIT_LAS */ >+ >+#define AUTHENAATVS &rad_realm_aatv, &rad_unix_aatv, &rad_2rad_aatv, \ >+ &rad_tacs_aatv, &rad_kchp_aatv, &rad_mnet_aatv, \ >+ &rad_akrb_aatv, &rad_mkrb_aatv, &rad_file_aatv, \ >+ &rad_authen_aatv, &rad_passwd_aatv, &rad_script_aatv >+ >+ >+#define AATVS AUTHENAATVS HGAATVS OASAATVS LASAATVS >+ >+/* >+ * Event names (EN_*) in RADIUS ### see the NOTE in enum_event() >+ */ >+ >+#define EN_NAK "NAK" >+#define EN_ACK "ACK" >+#define EN_ERROR "ERROR" >+#define EN_WAIT "WAIT" >+#define EN_FATAL "FATAL" >+#define EN_DUP_REQ "DUP" >+#define EN_TIMER "TIMER" >+#define EN_TIMEOUT "TIMEOUT" >+#define EN_ABORT "ABORT" >+#define EN_NEW_AUTHEN "AUTHEN" >+#define EN_NEW_ACCT "ACCT" >+#define EN_NEW_PASSWD "PASSWD" >+#define EN_RE_ACCESS "REACCESS" >+#define EN_ACC_CHAL "ACC_CHAL" >+#define EN_MGT_POLL "MGT_POLL" >+#define EN_AUTH_ONLY "AUTH_ONLY" >+#define EN_ACCT_START "ACCT_START" >+#define EN_ACCT_STOP "ACCT_STOP" >+#define EN_ACCT_ALIVE "ACCT_ALIVE" >+#define EN_ACCT_MODEM_START "ACCT_MSTART" >+#define EN_ACCT_MODEM_STOP "ACCT_MSTOP" >+#define EN_ACCT_CANCEL "ACCT_CANCEL" >+#define EN_RC1 "RC1" >+#define EN_RC2 "RC2" >+#define EN_RC3 "RC3" >+#define EN_RC4 "RC4" >+#define EN_RC5 "RC5" >+#define EN_RC6 "RC6" >+#define EN_RC7 "RC7" >+#define EN_RC8 "RC8" >+#define EN_RC9 "RC9" >+#define EN_RC10 "RC10" >+#define EN_RC11 "RC11" >+#define EN_RC12 "RC12" >+#define EN_RC13 "RC13" >+#define EN_RC14 "RC14" >+#define EN_RC15 "RC15" >+#define EN_RC16 "RC16" >+#define EN_RC17 "RC17" >+#define EN_RC18 "RC18" >+#define EN_RC19 "RC19" >+#define EN_RC20 "RC20" >+#define EN_RC21 "RC21" >+ >+/* >+ * Event numbers in RADIUS ### see the NOTE in enum_event() >+ */ >+typedef enum >+{ >+ EV_NAK = -1, >+ EV_ACK = 0, >+ EV_ERROR = 1, >+ EV_WAIT = 2, >+ EV_FATAL = 3, >+ EV_DUP_REQ = 4, >+ EV_TIMER = 5, >+ EV_TIMEOUT = 6, >+ EV_ABORT = 7, >+ >+ /* arbitrary return codes from AATV action functions */ >+ >+ EV_RC1 = 8, >+ EV_RC2 = 9, >+ EV_RC3 = 10, >+ EV_RC4 = 11, >+ EV_RC5 = 12, >+ EV_RC6 = 13, >+ EV_RC7 = 14, >+ EV_RC8 = 15, >+ EV_RC9 = 16, >+ EV_RC10 = 17, >+ EV_RC11 = 18, >+ EV_RC12 = 19, >+ EV_RC13 = 20, >+ EV_RC14 = 21, >+ EV_RC15 = 22, >+ EV_RC16 = 23, >+ EV_RC17 = 24, >+ EV_RC18 = 25, >+ EV_RC19 = 26, >+ EV_RC20 = 27, >+ EV_RC21 = 28 >+} EVENT; >+ >+/* Request type events */ >+ >+#define EV_NEW_AUTHEN EV_RC1 >+#define EV_NEW_ACCT EV_RC2 >+#define EV_NEW_PASSWD EV_RC3 >+#define EV_RE_ACCESS EV_RC4 >+#define EV_ACC_CHAL EV_RC5 >+#define EV_MGT_POLL EV_RC6 >+#define EV_AUTH_ONLY EV_RC7 >+#ifdef MERIT_HUNTGROUP >+#define EV_HGAS1 EV_RC8 >+#define EV_HGAS2 EV_RC9 >+#define EV_HGAS3 EV_RC10 >+#define EV_BACCT EV_RC11 >+#else /* MERIT_HUNTGROUP */ >+#define EV_HGAS1 EV_ACK >+#define EV_HGAS2 EV_ACK >+#define EV_HGAS3 EV_ACK >+#define EV_BACCT EV_ACK >+#endif /* MERIT_HUNTGROUP */ >+#define EV_ACCT_START EV_RC12 >+#define EV_ACCT_STOP EV_RC13 >+#define EV_ACCT_ALIVE EV_RC14 >+#define EV_ACCT_MODEM_START EV_RC15 >+#define EV_ACCT_MODEM_STOP EV_RC16 >+#define EV_ACCT_CANCEL EV_RC17 >+#ifdef MERIT_ORGANIZATION >+#define EV_OAS EV_RC18 >+#define EV_OAS_ACCT EV_RC19 >+#else /* MERIT_ORGANIZATION */ >+#define EV_OAS EV_ACK >+#define EV_OAS_ACCT EV_ACK >+#endif /* MERIT_ORGANIZATION */ >+#ifdef MERIT_LAS >+#define EV_LAS EV_RC20 >+#define EV_LAS_ACCT EV_RC21 >+#else /* MERIT_LAS */ >+#define EV_LAS EV_ACK >+#define EV_LAS_ACCT EV_ACK >+#endif /* MERIT_LAS */ >+ >+typedef enum /* Typedef for second add_string() argument */ >+{ >+ ASIS = 0x0000, /* No conversion on string */ >+ ASLC = 0x0001, /* Store as lower case sting */ >+ FINDONLY = 0x0002 /* Find string only */ >+} AS_CONVERT; >+ >+/* >+ * The finite state machine (FSM) table is laid out as follows: >+ * >+ * state0: >+ * event01 aatv01 nextstate01 >+ * event02 aatv02 nextstate02 >+ * ... >+ * state1: >+ * event11 aatv11 nextstate11 >+ * ... >+ */ >+ >+#define NUMSTATES 32 /* initial maximum number of states */ >+ >+#define ST_INIT 0 /* initial state */ >+ >+#define ST_RESERVED 240 /* beginning of reserved state range */ >+#define ST_SEEN 241 /* flag for state seen before being defined */ >+#define ST_DEFINED 242 /* flag for state definition */ >+ >+#define ST_RECV 251 /* to indicate state which receives requests */ >+#define ST_HOLD 252 /* to indicate dead requests */ >+#define ST_SAME 253 /* for default action table */ >+#define ST_ANY 254 /* for default action table */ >+#define ST_END 255 /* end of FSM table */ >+ >+typedef struct statelist /* list of all state names */ >+{ >+ int maxst; /* capacity of this list */ >+ int nst; /* number of states already there */ >+ NAME_LIST *states; /* list of states found in the config file */ >+} STATELIST; >+ >+typedef struct fsm_entry /* The Finite State Machine an array of these */ >+{ >+ struct fsm_entry *next; /* list of entries for this state */ >+ EV event; /* (state.action.event) 3-tuple */ >+ AATV *action; /* what AATV (action) to invoke */ >+ int xvalue; /* miscellaneous integer from FSM */ >+ char *xstring; /* miscellaneous string from FSM */ >+ u_char next_state; /* the next state to visit */ >+} FSM_ENT; >+ >+typedef struct prun_rule /* Pruning data structure (from RADIUS DRAFT RFC) */ >+{ >+ int value; /* this is the attribute value */ >+ int flags; /* inclusive OR of PRUN_FLG values */ >+ int count; /* how many the RFC says to allow */ >+} PRUN_RULE; >+ >+typedef struct prun_list >+{ >+ char vendor[AUTH_ID_LEN + 1]; >+ PRUN_RULE *rules; >+ struct prun_list *next; >+} PRUN_LIST; >+ >+#define PRUN_FLG1 1 /* this attribute allowable in Access_Accept */ >+#define PRUN_FLG2 2 /* this attribute allowable in Access_Reject */ >+ >+#define AR_NO_LOG 0x01 /* sws: Suppress logging flag */ >+#define AR_FROM_PROXY 0x04 /* sws: authreq came from NAS */ >+ >+#define SAR_NO_LOG(authreq) (authreq->sws |= AR_NO_LOG) /* set flag */ >+#define CAR_NO_LOG(authreq) (authreq->sws &= ~AR_NO_LOG) /* clear flag */ >+#define TAR_NO_LOG(authreq) ((authreq->sws & AR_NO_LOG) != 0) /* test flag */ >+ >+#define SAR_FROM_PROXY(authreq) (authreq->sws |= AR_FROM_PROXY) /* set flag */ >+#define CAR_FROM_PROXY(authreq) (authreq->sws &= ~AR_FROM_PROXY) /* clr flag */ >+#define TAR_FROM_PROXY(authreq) ((authreq->sws & AR_FROM_PROXY) != 0) /* test */ >+ >+#define AVPAIR_VTOA_QUOTE 0x0001 /* Quote strings with "'" */ >+#define AVPAIR_VTOA_NULL 0x0002 /* Print "" instead of NULL for missing item */ >+#define AVPAIR_VTOA_MASK 0x00ff /* Reserve fourteen more bits. */ >+ >+#define LOG_VP_QUOTE 0x0001 /* Quote strings (same as AVPAIR_VTOA_QUOTE) */ >+#define LOG_VP_NULL 0x0002 /* Use "" (incompatible with LOG_VP_NA) */ >+#define LOG_VP_TAB 0x0100 /* Put tab after printing. */ >+#define LOG_VP_NA 0x0200 /* fprintf ("NA") if no attr exists in list. */ >+#define LOG_VP_LAST 0x0400 /* Log last value pair found. */ >+#define LOG_VP_ALL 0x0800 /* Log all attributes found. */ >+#define LOG_VP_MASK 0xFFFF /* Switches available. */ >+ >+/* dict.c */ >+int dict_init PROTO((void)); >+DICT_ATTR * dict_attrget PROTO((int)); >+DICT_ATTR * dict_attrfind PROTO((char *)); >+DICT_VALUE * dict_valfind PROTO((char *)); >+DICT_VALUE * dict_valget PROTO((UINT4, char *)); >+ >+/* fsm.c */ >+/*AATV * find_aatv PROTO((char *)); >+int init_fsm PROTO((int, AATVPTR **, int, char *, FSM_ENT ***, FSM_ENT ***)); >+*/ >+/* funcs.c */ >+char * add_string PROTO((char *, int)); >+char * authtype_toa PROTO((int)); >+VALUE_PAIR * avpair_add PROTO((VALUE_PAIR **, int, void *, int)); >+int avpair_assign PROTO((VALUE_PAIR *, void *, int)); >+int avpair_copy PROTO((VALUE_PAIR **, VALUE_PAIR *, int)); >+int avpair_get PROTO((void *, VALUE_PAIR *, int)); >+VALUE_PAIR * avpair_new PROTO((int, void *, int)); >+char * avpair_vtoa PROTO((VALUE_PAIR *, int)); >+void compress_file PROTO((FILE **, char *)); >+void debug_list PROTO((FILE *, VALUE_PAIR *)); >+void debug_pair PROTO((FILE *, VALUE_PAIR *)); >+int dumpit PROTO((/* int, int, void *, int, int, char *, ...*/)); >+void fprint_attr_val PROTO((FILE *, VALUE_PAIR *)); >+VALUE_PAIR * gen_valpairs PROTO((AUTH_HDR *)); >+char * get_errmsg PROTO((void)); >+int get_passwd PROTO((AUTH_REQ *, char *, char *, char *)); >+VALUE_PAIR * get_vp PROTO((VALUE_PAIR *, UINT4)); >+VALUE_PAIR * get_last_vp PROTO((VALUE_PAIR *, UINT4)); >+int hex_dump PROTO((char *, char *, int, int)); >+void insert_vp PROTO((VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *)); >+int loghead PROTO(( /* va_alist */ )); >+int logit PROTO(( /* int facility, int level, char *format, ... */ )); >+void missing_attribute PROTO((AUTH_REQ *, char *, int, char *)); >+VALUE_PAIR * parse_realm PROTO((AUTH_REQ *)); >+int prune_pairs PROTO((AUTH_REQ *, PRUN_LIST *, int)); >+#define reply_message(authreq, msgno, msg) _reply_message(authreq, msgno, msg,__FILE__, __LINE__) >+int _reply_message PROTO((AUTH_REQ *, ERRORCODE, char *, char *, int)); >+int reply_sprintf PROTO(( /* int logsw, AUTHREQ *, char *format, ... */ )); >+int setupsock PROTO((struct sockaddr_in *, int)); >+void trunc_logfile PROTO((FILE **, char *)); >+char * type_string PROTO((AUTH_REQ *, VALUE_PAIR *)); >+ >+/* passchange.c */ >+/*int pw_expired PROTO((UINT4));*/ >+ >+/* radiusd.c */ >+/*AUTH_REQ * build_acct_req PROTO((AUTH_REQ *, int, char *, int, VALUE_PAIR *)); >+int call_action PROTO((AATV *, AUTH_REQ *, int, char *)); >+AUTH_REQ * rad_2rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *)); >+AUTH_REQ * rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *)); >+int radius_send PROTO((char *, u_int, char *, AUTH_REQ *, int)); >+void start_fsm PROTO((AUTH_REQ *, int, char *, char *)); >+*/ >+/* sesslog.c */ >+/*VALUE_PAIR *log_vp PROTO((FILE *, VALUE_PAIR *, int, int)); >+int logfmt_brief PROTO((FILE *, VALUE_PAIR *)); >+int logfmt_old PROTO((FILE *, VALUE_PAIR *, int)); >+int logfmt_v1_0 PROTO((FILE *, VALUE_PAIR *)); >+int logfmt_v1_1 PROTO((FILE *, VALUE_PAIR *)); >+int logfmt_v2_0 PROTO((FILE *, VALUE_PAIR *, int, u_short *)); >+int logfmt_v2_1 PROTO((FILE *, VALUE_PAIR *, int)); >+*/ >+/* users.c */ >+int add_file_list PROTO((char *)); >+void config_init PROTO((void)); >+int config_files PROTO((int, int, int)); >+void config_fini PROTO((void)); >+void dns_recv PROTO((struct sockaddr_in *, UINT4, int)); >+AUTH_ENTRY * find_auth_ent PROTO((char *, int, char*)); >+int find_auth_type PROTO((char *, int, char *, int *, char **, char **, char **)); >+int find_client PROTO((UINT4, char **, char **, char **)); >+int find_client_by_name PROTO((UINT4 *, char *, char **, char **)); >+int find_host_by_name PROTO((UINT4 *, char *)); >+void free_user_ent PROTO((USER_ENTRY *)); >+UINT4 get_our_addr PROTO((void)); >+char * ip_hostname PROTO((UINT4)); >+void list_cat PROTO((VALUE_PAIR **, VALUE_PAIR *)); >+void list_copy PROTO((VALUE_PAIR **, VALUE_PAIR *)); >+int pair_parse PROTO((char *, VALUE_PAIR **)); >+FILE_LIST * return_file_list PROTO((void)); >+int update_clients PROTO((void)); >+int user_find PROTO((char *, char *, int, VALUE_PAIR **, VALUE_PAIR **, int)); >+void user_gettime PROTO((char *, struct tm *)); >+int user_update PROTO((char *, VALUE_PAIR *, VALUE_PAIR*)); >+ >+/* util.c */ >+UINT4 get_ipaddr PROTO((char *)); >+int good_ipaddr PROTO((char *)); >+void list_free PROTO((VALUE_PAIR *)); >+ >+/* version.c */ >+/*char * version PROTO((void)); >+*/ >+/* pppradius.c */ >+int rad_auth PROTO((char *, char *)); >+int rad_acct_start PROTO((char *)); >+int rad_acct_stop PROTO((char *)); >+ >+int reqradius; >+char *RADIUS_name; >+ >+#endif /* RADIUS_H */ >diff -rPu pppd.old/sys-NeXT.c pppd/sys-NeXT.c >--- pppd.old/sys-NeXT.c Thu Jan 1 03:00:00 1970 >+++ pppd/sys-NeXT.c Wed Mar 25 05:17:22 1998 >@@ -0,0 +1,1703 @@ >+/* >+ * sys-next.c - System-dependent procedures for setting up >+ * PPP interfaces on NeXT 3.2/3.3 systems >+ * >+ * Copyright (c) 1989 Carnegie Mellon University. >+ * Copyright (c) 1994 Philippe-Andre Prindeville. >+ * All rights reserved. >+ * >+ * Redistribution and use in source and binary forms are permitted >+ * provided that the above copyright notice and this paragraph are >+ * duplicated in all such forms and that any documentation, >+ * advertising materials, and other materials related to such >+ * distribution and use acknowledge that the software was developed >+ * by Carnegie Mellon University. The name of the >+ * University may not be used to endorse or promote products derived >+ * from this software without specific prior written permission. >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED >+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. >+ */ >+ >+#ifndef lint >+static char rcsid[] = "$Id: sys-NeXT.c,v 1.9 1998/03/25 02:17:23 paulus Exp $"; >+#endif >+ >+#include <stdio.h> >+#include <syslog.h> >+#include <termios.h> >+#include <utmp.h> >+#include <unistd.h> >+#include <stdlib.h> >+#include <libc.h> >+#include <strings.h> >+#include <sys/types.h> >+#include <sys/file.h> >+#include <sys/socket.h> >+#include <sys/ioctl.h> >+#include <sys/time.h> >+#include <sys/errno.h> >+#include <sys/stat.h> >+#include <sys/fcntl.h> >+ >+#include <net/if.h> >+#include <net/ppp_defs.h> >+#include <net/if_ppp.h> >+#include <netdb.h> >+#include <netinet/in.h> >+#include <netinet/in_systm.h> >+#include <netinet/in_var.h> >+#if !(NS_TARGET >= 40) >+/* XXX get an error "duplicate member ip_v under 4.1 GAMMA */ >+#include <netinet/ip.h> >+#endif /* NS_TARGET */ >+#include <netinet/if_ether.h> >+#include <net/route.h> >+#include <netinet/in.h> >+ >+#include <netinfo/ni.h> >+ >+#include "pppd.h" >+ >+static int initdisc = -1; /* Initial TTY discipline */ >+static int initfdflags = -1; /* Initial file descriptor flags for fd */ >+static int ppp_fd = -1; /* fd which is set to PPP discipline */ >+static int loop_slave = -1; >+static int loop_master; >+static char loop_name[20]; >+ >+extern int errno; >+ >+static int restore_term; /* 1 => we've munged the terminal */ >+static struct termios inittermios; /* Initial TTY termios */ >+ >+static char *lock_file; >+ >+static int sockfd; /* socket for doing interface ioctls */ >+static int pppdev; /* +++ */ >+ >+#if defined(i386) && defined(HAS_BROKEN_IOCTL) >+#define ioctl myioctl >+#endif >+ >+static int if_is_up; /* the interface is currently up */ >+static u_int32_t default_route_gateway; /* gateway addr for default route */ >+static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */ >+ >+/* Prototypes for procedures local to this file. */ >+static int translate_speed __P((int)); >+static int baud_rate_of __P((int)); >+static int dodefaultroute __P((u_int32_t, int)); >+static int get_ether_addr __P((u_int32_t, struct sockaddr *)); >+static int ether_by_host __P((char *, struct ether_addr *)); >+ >+ >+/* >+ * sys_init - System-dependent initialization. >+ */ >+void >+sys_init() >+{ >+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); >+ setlogmask(LOG_UPTO(LOG_INFO)); >+ >+ /* Get an internet socket for doing socket ioctl's on. */ >+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { >+ syslog(LOG_ERR, "Couldn't create IP socket: %m"); >+ die(1); >+ } >+ >+ if((pppdev = open("/dev/ppp0", O_RDWR, O_NONBLOCK)) == NULL) >+ { >+ syslog(LOG_ERR, "Couldn't open /dev/ppp0: %m"); >+ die(1); >+ } >+ >+} >+ >+/* >+ * sys_cleanup - restore any system state we modified before exiting: >+ * mark the interface down, delete default route and/or proxy arp entry. >+ * This should call die() because it's called from die(). >+ */ >+void >+sys_cleanup() >+{ >+ struct ifreq ifr; >+ >+ if (if_is_up) { >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0 >+ && ((ifr.ifr_flags & IFF_UP) != 0)) { >+ ifr.ifr_flags &= ~IFF_UP; >+ ioctl(sockfd, SIOCSIFFLAGS, &ifr); >+ } >+ } >+ >+ if (default_route_gateway) >+ cifdefaultroute(0, 0, default_route_gateway); >+ if (proxy_arp_addr) >+ cifproxyarp(0, proxy_arp_addr); >+ >+ close(pppdev); >+} >+ >+/* >+ * note_debug_level - note a change in the debug level. >+ */ >+void >+note_debug_level() >+{ >+ if (debug) { >+ syslog(LOG_INFO, "Debug turned ON, Level %d", debug); >+ setlogmask(LOG_UPTO(LOG_DEBUG)); >+ } else { >+ setlogmask(LOG_UPTO(LOG_WARNING)); >+ } >+} >+ >+/* >+ * ppp_available - check whether the system has any ppp interfaces >+ * (in fact we check whether we can do an ioctl on ppp0). >+ */ >+int >+ppp_available() >+{ >+ int s, ok; >+ struct ifreq ifr; >+ extern char *no_ppp_msg; >+ >+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) >+ return 1; /* can't tell - maybe we're not root */ >+ >+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name)); >+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0; >+ close(s); >+ >+ no_ppp_msg = "\ >+This system lacks kernel support for PPP. To include PPP support\n\ >+in the kernel, please follow the steps detailed in the README.NeXT\n\ >+file in the ppp-2.2 distribution.\n"; >+ >+ return ok; >+} >+ >+/* >+ * establish_ppp - Turn the serial port into a ppp interface. >+ */ >+void >+establish_ppp(fd) >+ int fd; >+{ >+ int pppdisc = PPPDISC; >+ int x; >+ >+ if (ioctl(fd, TIOCGETD, &initdisc) < 0) { >+ syslog(LOG_ERR, "ioctl(TIOCGETD): %m"); >+ die(1); >+ } >+ if (ioctl(fd, TIOCSETD, &pppdisc) < 0) { >+ syslog(LOG_ERR, "ioctl(establish TIOCSETD): %m"); >+ die(1); >+ } >+ >+ /* >+ * Find out which interface we were given. >+ */ >+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); >+ die(1); >+ } >+ >+ /* >+ * Enable debug in the driver if requested. >+ */ >+ if (kdebugflag) { >+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_WARNING, "ioctl(PPPIOCGFLAGS): %m"); >+ } else { >+ x |= (kdebugflag & 0xFF) * SC_DEBUG; >+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) >+ syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m"); >+ } >+ } >+ >+ /* >+ * Set device for non-blocking reads so PPPD can poll for >+ * input from the kernel. >+ */ >+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1 >+ || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { >+ syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m"); >+ } >+ >+} >+ >+ >+/* >+ * disestablish_ppp - Restore the serial port to normal operation. >+ * This shouldn't call die() because it's called from die(). >+ */ >+void >+disestablish_ppp(fd) >+ int fd; >+{ >+ /* Reset non-blocking mode on fd. */ >+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0) >+ syslog(LOG_WARNING, "Couldn't restore device fd flags: %m"); >+ initfdflags = -1; >+ >+ /* Restore old line discipline. */ >+ if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0) >+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); >+ initdisc = -1; >+} >+ >+/* >+ * Check whether the link seems not to be 8-bit clean. >+ */ >+void >+clean_check() >+{ >+ int x; >+ char *s; >+ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) == 0) { >+ s = NULL; >+ switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) { >+ case SC_RCV_B7_0: >+ s = "bit 7 set to 1"; >+ break; >+ case SC_RCV_B7_1: >+ s = "bit 7 set to 0"; >+ break; >+ case SC_RCV_EVNP: >+ s = "odd parity"; >+ break; >+ case SC_RCV_ODDP: >+ s = "even parity"; >+ break; >+ } >+ if (s != NULL) { >+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); >+ syslog(LOG_WARNING, "All received characters had %s", s); >+ } >+ } >+} >+ >+/* >+ * List of valid speeds. >+ */ >+struct speed { >+ int speed_int, speed_val; >+} speeds[] = { >+#ifdef B50 >+ { 50, B50 }, >+#endif >+#ifdef B75 >+ { 75, B75 }, >+#endif >+#ifdef B110 >+ { 110, B110 }, >+#endif >+#ifdef B134 >+ { 134, B134 }, >+#endif >+#ifdef B150 >+ { 150, B150 }, >+#endif >+#ifdef B200 >+ { 200, B200 }, >+#endif >+#ifdef B300 >+ { 300, B300 }, >+#endif >+#ifdef B600 >+ { 600, B600 }, >+#endif >+#ifdef B1200 >+ { 1200, B1200 }, >+#endif >+#ifdef B1800 >+ { 1800, B1800 }, >+#endif >+#ifdef B2000 >+ { 2000, B2000 }, >+#endif >+#ifdef B2400 >+ { 2400, B2400 }, >+#endif >+#ifdef B3600 >+ { 3600, B3600 }, >+#endif >+#ifdef B4800 >+ { 4800, B4800 }, >+#endif >+#ifdef B7200 >+ { 7200, B7200 }, >+#endif >+#ifdef B9600 >+ { 9600, B9600 }, >+#endif >+#ifdef B19200 >+ { 19200, B19200 }, >+#endif >+#ifdef B38400 >+ { 38400, B38400 }, >+#endif >+#ifdef EXTA >+ { 19200, EXTA }, >+#endif >+#ifdef EXTB >+ { 38400, EXTB }, >+#endif >+#ifdef B14400 >+ { 14400, B14400 }, >+#endif >+#ifdef B28800 >+ { 28800, B28800 }, >+#endif >+#ifdef B43200 >+ { 43200, B43200 }, >+#endif >+#ifdef B57600 >+ { 57600, B57600 }, >+#endif >+/* >+#ifndef B115200 >+#warning Defining B115200 >+#define B115200 20 >+#endif >+*/ >+#ifdef B115200 >+ { 115200, B115200 }, >+#endif >+ { 0, 0 } >+}; >+ >+/* >+ * Translate from bits/second to a speed_t. >+ */ >+int >+translate_speed(bps) >+ int bps; >+{ >+ struct speed *speedp; >+ >+ if (bps == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (bps == speedp->speed_int) >+ return speedp->speed_val; >+ syslog(LOG_WARNING, "speed %d not supported", bps); >+ return 0; >+} >+ >+/* >+ * Translate from a speed_t to bits/second. >+ */ >+static int >+baud_rate_of(speed) >+ int speed; >+{ >+ struct speed *speedp; >+ >+ if (speed == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (speed == speedp->speed_val) >+ return speedp->speed_int; >+ return 0; >+} >+ >+ >+/* >+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, >+ * at the requested speed, etc. If `local' is true, set CLOCAL >+ * regardless of whether the modem option was specified. >+ */ >+void >+set_up_tty(fd, local) >+ int fd, local; >+{ >+ int speed, x, modembits; >+ struct termios tios; >+ >+ if (tcgetattr(fd, &tios) < 0) { >+ syslog(LOG_ERR, "tcgetattr: %m"); >+ die(1); >+ } >+ >+ if (!restore_term) >+ inittermios = tios; >+ >+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); >+ >+ tios.c_cflag |= CS8 | CREAD | HUPCL; >+ if (local || !modem) >+ tios.c_cflag |= CLOCAL; >+ >+ tios.c_iflag = IGNBRK | IGNPAR; >+ tios.c_oflag = 0; >+ tios.c_lflag = 0; >+ tios.c_cc[VMIN] = 1; >+ tios.c_cc[VTIME] = 0; >+ >+ if (crtscts == -2) { >+ tios.c_iflag |= IXON | IXOFF; >+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ >+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ >+ } >+ >+ speed = translate_speed(inspeed); >+ if (speed) { >+ cfsetospeed(&tios, speed); >+ cfsetispeed(&tios, speed); >+ } else { >+ speed = cfgetospeed(&tios); >+ /* >+ * We can't proceed if the serial port speed is B0, >+ * since that implies that the serial port is disabled. >+ */ >+ if (speed == B0) { >+ syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", >+ devnam); >+ die(1); >+ } >+ } >+ >+ if (modem) { >+ modembits = TIOCM_RTS | TIOCM_CTS; >+ if (ioctl(fd, (crtscts ? TIOCMBIS : TIOCMBIC), &modembits) < 0) >+ syslog(LOG_ERR, "ioctl: TIOCMBIS/BIC: %m"); >+ } >+ >+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { >+ syslog(LOG_ERR, "tcsetattr: %m"); >+ die(1); >+ } >+ >+ baud_rate = inspeed = baud_rate_of(speed); >+ restore_term = 1; >+} >+ >+/* >+ * restore_tty - restore the terminal to the saved settings. >+ */ >+void >+restore_tty(fd) >+ int fd; >+{ >+ if (restore_term) { >+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) >+ if (errno != ENXIO) >+ syslog(LOG_WARNING, "tcsetattr: %m"); >+ restore_term = 0; >+ } >+} >+ >+/* >+ * setdtr - control the DTR line on the serial port. >+ * This is called from die(), so it shouldn't call die(). >+ * >+ * The write hack is to get NXFax to recognize that there is >+ * activity on the port. Not using the write nukes >+ * NXFax's capability to determine port usage. >+ * >+ */ >+void >+setdtr(fd, on) >+int fd, on; >+{ >+ int modembits = TIOCM_DTR; >+ >+ if (!on) >+ { >+ write(fd, " ", 1); >+ sleep(1); >+ } >+ >+/* ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); */ >+ ioctl(fd, (on? TIOCSDTR: TIOCCDTR), 0); >+} >+ >+ >+/* >+ * output - Output PPP packet. >+ */ >+void >+output(unit, p, len) >+ int unit; >+ u_char *p; >+ int len; >+{ >+ if (debug) >+ log_packet(p, len, "sent ", LOG_DEBUG); >+ >+ if (write(ttyfd, p, len) < 0) { >+ if (errno == EWOULDBLOCK || errno == ENOBUFS >+ || errno == ENXIO || errno == EIO) { >+ syslog(LOG_WARNING, "write: warning: %m"); >+ } else { >+ syslog(LOG_ERR, "write: %m"); >+ die(1); >+ } >+ } >+} >+ >+ >+/* >+ * wait_input - wait until there is data available on ttyfd, >+ * for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_input(timo) >+ struct timeval *timo; >+{ >+ fd_set ready; >+ int n; >+ >+ FD_ZERO(&ready); >+ FD_SET(ttyfd, &ready); >+ n = select(ttyfd+1, &ready, NULL, &ready, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >+ >+ >+/* >+ * read_packet - get a PPP packet from the serial device. >+ */ >+int >+read_packet(buf) >+ u_char *buf; >+{ >+ int len; >+ >+ if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) { >+ if (errno == EWOULDBLOCK || errno == EINTR) { >+ MAINDEBUG((LOG_DEBUG, "read: %m")); >+ return -1; >+ } >+ syslog(LOG_ERR, "read: %m"); >+ die(1); >+ } >+ return len; >+} >+ >+ >+/* >+ * ppp_send_config - configure the transmit characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) >+ int unit, mtu; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ u_int x; >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); >+ ifr.ifr_mtu = mtu; >+ if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); >+ quit(); >+ } >+ >+ if (ioctl(ttyfd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m"); >+ quit(); >+ } >+ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); >+ quit(); >+ } >+ x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT; >+ x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+ quit(); >+ } >+} >+ >+ >+/* >+ * ppp_set_xaccm - set the extended transmit ACCM for the interface. >+ */ >+void >+ppp_set_xaccm(unit, accm) >+ int unit; >+ ext_accm accm; >+{ >+ if (ioctl(ttyfd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) >+ syslog(LOG_WARNING, "ioctl(PPPIOCSXASYNCMAP): %m"); >+} >+ >+ >+/* >+ * ppp_recv_config - configure the receive-side characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) >+ int unit, mru; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int x; >+ >+ if (ioctl(ttyfd, PPPIOCSMRU, (caddr_t) &mru) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m"); >+ quit(); >+ } >+ if (ioctl(ttyfd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m"); >+ quit(); >+ } >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); >+ quit(); >+ } >+ x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+ quit(); >+ } >+} >+ >+/* >+ * ccp_test - ask kernel whether a given compression method >+ * is acceptable for use. >+ */ >+int >+ccp_test(unit, opt_ptr, opt_len, for_transmit) >+ int unit, opt_len, for_transmit; >+ u_char *opt_ptr; >+{ >+ struct ppp_option_data data; >+ >+ data.ptr = opt_ptr; >+ data.length = opt_len; >+ data.transmit = for_transmit; >+ if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0) >+ return 1; >+ return (errno == ENOBUFS)? 0: -1; >+} >+ >+/* >+ * ccp_flags_set - inform kernel about the current state of CCP. >+ */ >+void >+ccp_flags_set(unit, isopen, isup) >+ int unit, isopen, isup; >+{ >+ int x; >+ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); >+ return; >+ } >+ x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN; >+ x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+} >+ >+/* >+ * ccp_fatal_error - returns 1 if decompression was disabled as a >+ * result of an error detected after decompression of a packet, >+ * 0 otherwise. This is necessary because of patent nonsense. >+ */ >+int >+ccp_fatal_error(unit) >+ int unit; >+{ >+ int x; >+ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); >+ return 0; >+ } >+ return x & SC_DC_FERROR; >+} >+ >+/* >+ * sifvjcomp - config tcp header compression >+ */ >+int >+sifvjcomp(u, vjcomp, cidcomp, maxcid) >+ int u, vjcomp, cidcomp, maxcid; >+{ >+ u_int x; >+ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPIOCGFLAGS): %m"); >+ return 0; >+ } >+ x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP; >+ x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+ return 0; >+ } >+ if (ioctl(ttyfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+ return 0; >+ } >+ return 1; >+} >+ >+/* >+ * sifup - Config the interface up and enable IP packets to pass. >+ */ >+#ifndef SC_ENABLE_IP >+#define SC_ENABLE_IP 0x100 /* compat for old versions of kernel code */ >+#endif >+ >+int >+sifup(u) >+ int u; >+{ >+ struct ifreq ifr; >+ u_int x; >+ struct npioctl npi; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); >+ return 0; >+ } >+ ifr.ifr_flags |= IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); >+ return 0; >+ } >+ if_is_up = 1; >+ npi.protocol = PPP_IP; >+ npi.mode = NPMODE_PASS; >+ if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) { >+ if (errno != ENOTTY) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m"); >+ return 0; >+ } >+ /* for backwards compatibility */ >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); >+ return 0; >+ } >+ x |= SC_ENABLE_IP; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); >+ return 0; >+ } >+ } >+ return 1; >+} >+ >+/* >+ * sifdown - Config the interface down and disable IP. >+ */ >+int >+sifdown(u) >+ int u; >+{ >+ struct ifreq ifr; >+ u_int x; >+ int rv; >+ struct npioctl npi; >+ >+ rv = 1; >+ npi.protocol = PPP_IP; >+ npi.mode = NPMODE_ERROR; >+ ioctl(ttyfd, PPPIOCSNPMODE, (caddr_t) &npi); >+ /* ignore errors, because ttyfd might have been closed by now. */ >+ >+ >+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); >+ rv = 0; >+ } else { >+ ifr.ifr_flags &= ~IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); >+ rv = 0; >+ } else >+ if_is_up = 0; >+ } >+ return rv; >+} >+ >+/* >+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, >+ * if it exists. >+ */ >+#define SET_SA_FAMILY(addr, family) \ >+ BZERO((char *) &(addr), sizeof(addr)); \ >+ addr.sa_family = (family); >+ >+/* >+ * sifaddr - Config the interface IP addresses and netmask. >+ */ >+int >+sifaddr(u, o, h, m) >+ int u; >+ u_int32_t o, h, m; >+{ >+ int ret; >+ struct ifreq ifr; >+ >+ ret = 1; >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET); >+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; >+ if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m"); >+ ret = 0; >+ } >+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h; >+ if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); >+ ret = 0; >+ } >+ if (m != 0) { >+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m; >+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); >+ if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m"); >+ ret = 0; >+ } >+ } >+ return ret; >+} >+ >+/* >+ * cifaddr - Clear the interface IP addresses, and delete routes >+ * through the interface if possible. >+ * >+ * N.B.: under NextStep, you can't *delete* an address on an interface, >+ * so we change it to 0.0.0.0... A real hack. But it simplifies >+ * reconnection on the server side. >+ */ >+int >+cifaddr(u, o, h) >+ int u; >+ u_int32_t o, h; >+{ >+ struct rtentry rt; >+ >+#if 1 >+ h = o = 0L; >+ (void) sifaddr(u, o, h, 0L); >+#endif >+ SET_SA_FAMILY(rt.rt_dst, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; >+ SET_SA_FAMILY(rt.rt_gateway, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; >+ rt.rt_flags = RTF_HOST; >+ if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); >+ return 0; >+ } >+ return 1; >+} >+ >+/* >+ * sifdefaultroute - assign a default route through the address given. >+ */ >+int >+sifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ return dodefaultroute(g, 's'); >+} >+ >+/* >+ * cifdefaultroute - delete a default route through the address given. >+ */ >+int >+cifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ return dodefaultroute(g, 'c'); >+} >+ >+/* >+ * dodefaultroute - talk to a routing socket to add/delete a default route. >+ */ >+int >+dodefaultroute(g, cmd) >+ u_int32_t g; >+ int cmd; >+{ >+ struct rtentry rt; >+ >+ SET_SA_FAMILY(rt.rt_dst, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = 0L; >+ SET_SA_FAMILY(rt.rt_gateway, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; >+ rt.rt_flags = RTF_GATEWAY; >+ if (ioctl(sockfd, (cmd == 's') ? SIOCADDRT : SIOCDELRT, &rt) < 0) { >+ syslog(LOG_ERR, "%cifdefaultroute: ioctl(%s): %m", cmd, >+ (cmd == 's') ? "SIOCADDRT" : "SIOCDELRT"); >+ return 0; >+ } >+ default_route_gateway = (cmd == 's')? g: 0; >+ return 1; >+} >+ >+/* >+ * sifproxyarp - Make a proxy ARP entry for the peer. >+ */ >+int >+sifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ BZERO(&arpreq, sizeof(arpreq)); >+ >+ /* >+ * Get the hardware address of an interface on the same subnet >+ * as our local address. >+ */ >+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) { >+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP"); >+ return 0; >+ } >+ >+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET); >+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; >+ arpreq.arp_flags = ATF_PERM | ATF_PUBL; >+ if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = hisaddr; >+ return 1; >+} >+ >+/* >+ * cifproxyarp - Delete the proxy ARP entry for the peer. >+ */ >+int >+cifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ BZERO(&arpreq, sizeof(arpreq)); >+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET); >+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; >+ if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m"); >+ return 0; >+ } >+ proxy_arp_addr = 0; >+ return 1; >+} >+ >+/* >+ * get_ether_addr - get the hardware address of an interface on the >+ * the same subnet as ipaddr. >+ */ >+#define MAX_IFS 32 >+ >+int >+get_ether_addr(ipaddr, hwaddr) >+ u_int32_t ipaddr; >+ struct sockaddr *hwaddr; >+{ >+ struct ifreq *ifr, *ifend, *ifp; >+ u_int32_t ina, mask; >+ struct ether_addr dla; >+ struct ifreq ifreq; >+ struct ifconf ifc; >+ struct ifreq ifs[MAX_IFS]; >+ struct hostent *hostent; >+ >+ ifc.ifc_len = sizeof(ifs); >+ ifc.ifc_req = ifs; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m"); >+ return 0; >+ } >+ >+ /* >+ * Scan through looking for an interface with an Internet >+ * address on the same subnet as `ipaddr'. >+ */ >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *) >+ ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) { >+ if (ifr->ifr_addr.sa_family == AF_INET) { >+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ /* >+ * Check that the interface is up, and not point-to-point >+ * or loopback. >+ */ >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & >+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) >+ != (IFF_UP|IFF_BROADCAST)) >+ continue; >+ /* >+ * Get its netmask and check that it's on the right subnet. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ mask = ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr; >+ if ((ipaddr & mask) != (ina & mask)) >+ continue; >+ >+ break; >+ } >+ } >+ >+ if (ifr >= ifend) >+ return 0; >+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name); >+ >+ /* >+ * Get the hostname and look for an entry using the ethers database. >+ * Under NeXTStep this is the best we can do for now. >+ */ >+ if ((hostent = gethostbyaddr((char*)&ina, sizeof(ina), AF_INET)) == NULL) >+ return 0; >+ >+ if (ether_by_host(hostent->h_name, &dla)) { >+ syslog(LOG_INFO, "Add entry for %s in /etc/ethers", hostent->h_name); >+ return 0; /* it's not there */ >+ } >+ hwaddr->sa_family = AF_UNSPEC; >+ BCOPY(&dla, hwaddr->sa_data, sizeof(dla)); >+ return 1; >+} >+ >+static int >+ether_by_host(hostname, etherptr) >+ char *hostname; >+ struct ether_addr *etherptr; >+{ >+ struct ether_addr *thisptr; >+ void *conn; >+ ni_id root; >+ ni_namelist val; >+ char path[256]; >+ >+ if (!ether_hostton(hostname, etherptr)) >+ return 0; >+ /* >+ * We shall now try and >+ * find the address in the >+ * top domain of netinfo. >+ */ >+ strcat(strcpy(path, "/machines/"), hostname); >+ >+ if (ni_open((void *)0, "/", &conn) >+ || ni_root(conn, &root) >+ || ni_pathsearch(conn, &root, path) >+ || ni_lookupprop(conn, &root, "en_address", &val)) >+ return 1; >+ >+ /* >+ * Now we can convert the returned string into an ethernet address. >+ */ >+ strcpy(path, val.ni_namelist_val[0]); >+ ni_free(conn); >+ if ((thisptr = (struct ether_addr*)ether_aton(path)) == NULL) >+ return 1; >+ BCOPY(thisptr, etherptr, sizeof(struct ether_addr)); >+ return 0; >+} >+ >+ >+ >+/* >+ * Return user specified netmask, modified by any mask we might determine >+ * for address `addr' (in network byte order). >+ * Here we scan through the system's list of interfaces, looking for >+ * any non-point-to-point interfaces which might appear to be on the same >+ * network as `addr'. If we find any, we OR in their netmask to the >+ * user-specified netmask. >+ */ >+u_int32_t >+GetMask(addr) >+ u_int32_t addr; >+{ >+ u_int32_t mask, nmask, ina; >+ struct ifreq *ifr, *ifend, ifreq; >+ struct ifconf ifc; >+ struct ifreq ifs[MAX_IFS]; >+ >+ addr = ntohl(addr); >+ if (IN_CLASSA(addr)) /* determine network mask for address class */ >+ nmask = IN_CLASSA_NET; >+ else if (IN_CLASSB(addr)) >+ nmask = IN_CLASSB_NET; >+ else >+ nmask = IN_CLASSC_NET; >+ /* class D nets are disallowed by bad_ip_adrs */ >+ mask = netmask | htonl(nmask); >+ >+ /* >+ * Scan through the system's network interfaces. >+ */ >+ ifc.ifc_len = sizeof(ifs); >+ ifc.ifc_req = ifs; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m"); >+ return mask; >+ } >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *) >+ ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) { >+ /* >+ * Check the interface's internet address. >+ */ >+ if (ifr->ifr_addr.sa_family != AF_INET) >+ continue; >+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; >+ if ((ntohl(ina) & nmask) != (addr & nmask)) >+ continue; >+ /* >+ * Check that the interface is up, and not point-to-point or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) >+ != IFF_UP) >+ continue; >+ /* >+ * Get its netmask and OR it into our mask. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; >+ } >+ >+ return mask; >+} >+ >+ >+ >+/* >+ * daemon - Detach us from the terminal session. >+ */ >+int >+daemon(nochdir, noclose) >+ int nochdir, noclose; >+{ >+ int pid; >+ >+ if ((pid = fork()) < 0) >+ return -1; >+ if (pid != 0) >+ exit(0); /* parent dies */ >+ (void)setsid(); >+ if (!nochdir) >+ chdir("/"); >+ if (!noclose) { >+ fclose(stdin); /* don't need stdin, stdout, stderr */ >+ fclose(stdout); >+ fclose(stderr); >+ } >+ return 0; >+} >+ >+ >+char * >+strdup(s) >+ const char *s; >+{ >+ char *d = malloc(strlen(s) + 1); >+ >+ if (d) strcpy(d, s); >+ return d; >+} >+ >+/* >+ * This logwtmp() implementation is subject to the following copyright: >+ * >+ * Copyright (c) 1988 The Regents of the University of California. >+ * All rights reserved. >+ * >+ * Redistribution and use in source and binary forms are permitted >+ * provided that the above copyright notice and this paragraph are >+ * duplicated in all such forms and that any documentation, >+ * advertising materials, and other materials related to such >+ * distribution and use acknowledge that the software was developed >+ * by the University of California, Berkeley. The name of the >+ * University may not be used to endorse or promote products derived >+ * from this software without specific prior written permission. >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED >+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. >+ */ >+ >+#define WTMPFILE "/usr/adm/wtmp" >+ >+void >+logwtmp(line, name, host) >+ const char *line, *name, *host; >+{ >+ int fd; >+ struct stat buf; >+ struct utmp ut; >+ >+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) >+ return; >+ if (!fstat(fd, &buf)) { >+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); >+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); >+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); >+ (void)time(&ut.ut_time); >+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) >+ (void)ftruncate(fd, buf.st_size); >+ } >+ close(fd); >+} >+ >+/* >+ * Routines for locking and unlocking the serial device, moved here >+ * from chat.c. >+ */ >+ >+#define LOCK_PREFIX "/usr/spool/uucp/LCK/LCK.." >+ >+/* >+ * lock - create a lock file for the named device >+ */ >+int >+lock(dev) >+ char *dev; >+{ >+ int fd, pid, n; >+ char *p; >+ >+ if ((p = strrchr(dev, '/')) != NULL) >+ dev = p + 1; >+ lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); >+ if (lock_file == NULL) >+ novm("lock file name"); >+ strcat(strcpy(lock_file, LOCK_PREFIX), dev); >+ >+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { >+ if (errno == EEXIST >+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { >+ /* Read the lock file to find out who has the device locked */ >+ n = read(fd, &pid, sizeof(pid)); >+ if (n <= 0) { >+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); >+ close(fd); >+ } else { >+ if (kill(pid, 0) == -1 && errno == ESRCH) { >+ /* pid no longer exists - remove the lock file */ >+ if (unlink(lock_file) == 0) { >+ close(fd); >+ syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", >+ dev, pid); >+ continue; >+ } else >+ syslog(LOG_WARNING, "Couldn't remove stale lock on %s", >+ dev); >+ } else >+ syslog(LOG_NOTICE, "Device %s is locked by pid %d", >+ dev, pid); >+ } >+ close(fd); >+ } else >+ syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ return -1; >+ } >+ >+ pid = getpid(); >+ write(fd, &pid, sizeof pid); >+ >+ close(fd); >+ return 0; >+} >+ >+/* >+ * unlock - remove our lockfile >+ */ >+void >+unlock() >+{ >+ if (lock_file) { >+ unlink(lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ } >+} >+ >+#if defined(i386) && defined(HAS_BROKEN_IOCTL) >+int >+ioctl(fd, cmd, c) >+ int fd, cmd; >+ caddr_t c; >+{ >+#undef ioctl >+ int ret; >+ >+#ifdef DEBUGIOCTL >+ int serrno; >+ u_char let, code, size; >+ >+ size = (cmd >> 16) & IOCPARM_MASK; >+ let = (cmd >> 8); >+ code = cmd; >+ >+ if (let == 't' && (75 <= code && code <= 90)) >+ syslog(LOG_INFO, "ioctl(%d, 0x%x ('%c', %d, %d), 0x%x)\n", fd, cmd, >+ let, code, size, c); >+#endif >+ >+ ret = ioctl(fd, cmd, c); >+ >+#ifdef DEBUGIOCTL >+ serrno = errno; >+ if (ret == -1) >+ syslog(LOG_INFO, "ioctl('%c', %d, %d) errno = %d (%m)\n", >+ let, code, size, errno); >+ if (let == 't' && (75 <= code && code <= 90) && (cmd & IOC_OUT)) { >+ int i, len = ((cmd >> 16) & IOCPARM_MASK); >+ for (i = 0; i < len / 4; ++i) >+ syslog(LOG_INFO, "word[%d] @ 0x%06x = 0x%x\n", >+ i, &((int *) c)[i],((int *)c)[i]); >+ } >+ errno = serrno; >+#endif >+ >+ if (ret == -1 && errno == EPERM) >+ errno = ret = 0; >+ return ret; >+} >+#endif /* HAS_BROKEN_IOCTL */ >+ >+ >+#if defined(FIXSIGS) && (defined (hppa) || defined(sparc)) >+ >+/* >+ * These redefinitions of Posix functions are necessary >+ * because HPPA systems have an OS bug that causes >+ * sigaction to core dump: >+ * >+ * AlainF 9-Nov-1994 HACK FOR HP-PA/NEXTSTEP >+ * sigaction(3) seems broken in the HP-PA NeXTSTEP 3.2 >+ * Posix lib. This causes pppd to SIGBUS at the expiration >+ * of the first timeout (_sigtramp seems to invoke >+ * the SIGALRM handler at an unreasonably low address). >+ * All calls so sigaction(3) have been changed to calls >+ * to sigvec(2) and sigprocmask(SIG_BLOCK,...) to >+ * sigblock(2). >+ * This is kind of a hack, especially since there are >+ * other routines of the Posix lib still used, but >+ * it worked for me. >+ * >+ * Dave Hess <David-Hess@net.tamu.edu> noted that 3.3 Sparc seems to >+ * have the same bug. Thus this fix has been enabled for SPARC also. >+ * >+ * >+ */ >+ >+int sigemptyset(sigset_t *mask) >+{ >+ *mask = 0; >+} >+ >+sigaddset(sigset_t *mask, int which_sig) >+{ >+ *mask |= sigmask(which_sig); >+} >+ >+ >+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) >+{ >+ struct sigvec sv; >+ static int in = 0; >+ >+ sv.sv_handler = act->sa_handler; >+ sv.sv_mask = act->sa_mask; >+ sv.sv_flags = 0; >+ >+ if (!in) >+ { >+ in = 1; >+ syslog(LOG_WARNING, "PPPD: Inside modified HP and SPARC sigaction\n"); >+ } >+ >+ return sigvec(sig, &sv, NULL); >+} >+ >+#endif >+ >+ >+/* >+ * Code following is added for 2.3 compatibility >+ */ >+ >+/* >+ * get_idle_time - return how long the link has been idle. >+ */ >+int >+get_idle_time(u, ip) >+ int u; >+ struct ppp_idle *ip; >+{ >+ return (ioctl(ttyfd, PPPIOCGIDLE, ip) >= 0); >+} >+ >+ >+/* >+ * get_loop_output - read characters from the loopback, form them >+ * into frames, and detect when we want to bring the real link up. >+ * Return value is 1 if we need to bring up the link, 0 otherwise. >+ */ >+int >+get_loop_output() >+{ >+ >+#if 0 >+ int rv = 0; >+ int n; >+ >+ while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) { >+ if (loop_chars(inbuf, n)) >+ rv = 1; >+ } >+ >+ if (n == 0) { >+ syslog(LOG_ERR, "eof on loopback"); >+ die(1); >+ } else if (errno != EWOULDBLOCK){ >+ syslog(LOG_ERR, "read from loopback: %m"); >+ die(1); >+ } >+ >+ return rv; >+#endif >+ >+ return 0; >+} >+ >+/* >+ * sifnpmode - Set the mode for handling packets for a given NP. >+ */ >+int >+sifnpmode(u, proto, mode) >+ int u; >+ int proto; >+ enum NPmode mode; >+{ >+ struct npioctl npi; >+ >+ npi.protocol = proto; >+ npi.mode = mode; >+ if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) { >+ syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode); >+ return 0; >+ } >+ return 1; >+} >+ >+ >+/* >+ * open_ppp_loopback - open the device we use for getting >+ * packets in demand mode, and connect it to a ppp interface. >+ * Here we use a pty. >+ */ >+void >+open_ppp_loopback() >+{ >+ >+#if 0 >+ int flags; >+ struct termios tios; >+ int pppdisc = PPPDISC; >+ >+ syslog(LOG_ERR, "open_ppp_loopback called!"); >+ die(1); >+ >+ if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0) { >+ syslog(LOG_ERR, "No free pty for loopback"); >+ die(1); >+ } >+ SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name)); >+ >+ if (tcgetattr(loop_slave, &tios) == 0) { >+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); >+ tios.c_cflag |= CS8 | CREAD; >+ tios.c_iflag = IGNPAR; >+ tios.c_oflag = 0; >+ tios.c_lflag = 0; >+ if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0) >+ syslog(LOG_WARNING, "couldn't set attributes on loopback: %m"); >+ } >+ >+ if ((flags = fcntl(loop_master, F_GETFL)) != -1) >+ if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1) >+ syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m"); >+ >+ ttyfd = loop_slave; >+ if (ioctl(ttyfd, TIOCSETD, &pppdisc) < 0) { >+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); >+ die(1); >+ } >+ >+ /* >+ * Find out which interface we were given. >+ */ >+ if (ioctl(ttyfd, PPPIOCGUNIT, &ifunit) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); >+ die(1); >+ } >+ >+ /* >+ * Enable debug in the driver if requested. >+ */ >+ if (kdebugflag) { >+ if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) { >+ syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m"); >+ } else { >+ flags |= (kdebugflag & 0xFF) * SC_DEBUG; >+ if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) >+ syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m"); >+ } >+ } >+ >+#endif >+ >+} >+ >+/* >+ * restore_loop - reattach the ppp unit to the loopback. >+ */ >+void >+restore_loop() >+{ >+ int x; >+ >+ /* >+ * Transfer the ppp interface back to the loopback. >+ */ >+ if (ioctl(ttyfd, PPPIOCXFERUNIT, 0) < 0) { >+ syslog(LOG_ERR, "ioctl(transfer ppp unit): %m"); >+ die(1); >+ } >+ x = PPPDISC; >+ if (ioctl(loop_slave, TIOCSETD, &x) < 0) { >+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); >+ die(1); >+ } >+ >+ /* >+ * Check that we got the same unit again. >+ */ >+ if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0) { >+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); >+ die(1); >+ } >+ if (x != ifunit) { >+ syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d", >+ ifunit, x); >+ die(1); >+ } >+ ttyfd = loop_slave; >+} >+ >+ >+/* >+ * Use the hostid as part of the random number seed. >+ */ >+int >+get_host_seed() >+{ >+ return gethostid(); >+} >+ >+ >+/* >+ * sys_check_options - check the options that the user specified >+ */ >+void >+sys_check_options() >+{ >+ /* >+ * We don't support demand dialing yet. >+ */ >+ if(demand) >+ { >+ syslog(LOG_WARNING, "PPP-2.3 for NeXTSTEP does not yet support demand dialing\n"); >+ demand = 0; >+ } >+} >+ >+ >+/* >+ * sys_close - Clean up in a child process before execing. >+ */ >+void >+sys_close() >+{ >+ close(sockfd); >+ if (loop_slave >= 0) { >+ close(loop_slave); >+ close(loop_master); >+ } >+ closelog(); >+} >+ >+ >+/* >+ * wait_loop_output - wait until there is data available on the >+ * loopback, for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void wait_loop_output(timo) >+ struct timeval *timo; >+{ >+ fd_set ready; >+ int n; >+ >+ FD_ZERO(&ready); >+ FD_SET(loop_master, &ready); >+ n = select(loop_master + 1, &ready, NULL, &ready, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >+ >+ >+/* >+ * wait_time - wait for a given length of time or until a >+ * signal is received. >+ */ >+void wait_time(timo) >+ struct timeval *timo; >+{ >+ int n; >+ >+ n = select(0, NULL, NULL, NULL, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >diff -rPu pppd.old/sys-osf.c pppd/sys-osf.c >--- pppd.old/sys-osf.c Thu Jan 1 03:00:00 1970 >+++ pppd/sys-osf.c Wed Mar 25 05:19:26 1998 >@@ -0,0 +1,1661 @@ >+/* >+ * System-dependent procedures for pppd under Digital UNIX (OSF/1). >+ * >+ * Copyright (c) 1994 The Australian National University. >+ * All rights reserved. >+ * >+ * Permission to use, copy, modify, and distribute this software and its >+ * documentation is hereby granted, provided that the above copyright >+ * notice appears in all copies. This software is provided without any >+ * warranty, express or implied. The Australian National University >+ * makes no representations about the suitability of this software for >+ * any purpose. >+ * >+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY >+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES >+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF >+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY >+ * OF SUCH DAMAGE. >+ * >+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, >+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY >+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS >+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO >+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, >+ * OR MODIFICATIONS. >+ */ >+ >+#ifndef lint >+static char rcsid[] = "$Id: sys-osf.c,v 1.13 1998/03/25 02:19:27 paulus Exp $"; >+#endif >+ >+#include <stdio.h> >+#include <stddef.h> >+#include <stdlib.h> >+#include <string.h> >+#include <ctype.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <unistd.h> >+#include <termios.h> >+#include <signal.h> >+#include <malloc.h> >+#include <utmp.h> >+#include <sys/types.h> >+#include <sys/param.h> >+#include <sys/socket.h> >+#include <sys/stream.h> >+#include <sys/stropts.h> >+#include <sys/syslog.h> >+#include <sys/stat.h> >+#include <sys/time.h> >+#include <sys/poll.h> >+#include <net/if.h> >+#include <net/if_arp.h> >+#include <net/route.h> >+#include <net/ppp_defs.h> >+#include <net/pppio.h> >+#include <netinet/in.h> >+ >+#include "pppd.h" >+ >+static int pppfd; >+static int fdmuxid = -1; >+static int iffd; >+static int sockfd; >+ >+static int restore_term; >+static struct termios inittermios; >+static struct winsize wsinfo; /* Initial window size info */ >+static pid_t tty_sid; /* PID of our session leader */ >+ >+extern u_char inpacket_buf[]; /* borrowed from main.c */ >+ >+static int link_mtu, link_mru; >+ >+#define NMODULES 32 >+static int tty_nmodules; >+static char tty_modules[NMODULES][FMNAMESZ+1]; >+ >+static int closed_stdio; >+static int initfdflags = -1; >+static int orig_ttyfd = -1; >+ >+static int if_is_up; /* Interface has been marked up */ >+static u_int32_t ifaddrs[2]; /* local and remote addresses */ >+static u_int32_t default_route_gateway; /* Gateway for default route added */ >+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ >+ >+/* Prototypes for procedures local to this file. */ >+static int translate_speed __P((int)); >+static int baud_rate_of __P((int)); >+static int get_ether_addr __P((u_int32_t, struct sockaddr *)); >+static int strioctl __P((int, int, void *, int, int)); >+ >+ >+/* >+ * sys_init - System-dependent initialization. >+ */ >+void >+sys_init() >+{ >+ int x; >+ >+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); >+ setlogmask(LOG_UPTO(LOG_INFO)); >+ if (debug) >+ setlogmask(LOG_UPTO(LOG_DEBUG)); >+ >+ /* Get an internet socket for doing socket ioctl's on. */ >+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { >+ syslog(LOG_ERR, "Couldn't create IP socket: %m"); >+ die(1); >+ } >+ >+ if (default_device) >+ tty_sid = getsid((pid_t)0); >+ >+ /* >+ * Open the ppp device. >+ */ >+ pppfd = open("/dev/streams/ppp", O_RDWR | O_NONBLOCK, 0); >+ if (pppfd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/streams/ppp: %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ >+ /* Assign a new PPA and get its unit number. */ >+ if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Can't create new PPP interface: %m"); >+ die(1); >+ } >+ >+ /* >+ * Open the ppp device again and push the if_ppp module on it. >+ */ >+ iffd = open("/dev/streams/ppp", O_RDWR, 0); >+ if (iffd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/streams/ppp (2): %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't attach ppp interface to device: %m"); >+ die(1); >+ } >+ if (ioctl(iffd, I_PUSH, "if_ppp") < 0) { >+ syslog(LOG_ERR, "Can't push ppp interface module: %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_IF; >+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't create ppp interface unit: %m"); >+ die(1); >+ } >+ x = PPP_IP; >+ if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't bind ppp interface to IP SAP: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * sys_cleanup - restore any system state we modified before exiting: >+ * mark the interface down, delete default route and/or proxy arp entry. >+ * This shouldn't call die() because it's called from die(). >+ */ >+void >+sys_cleanup() >+{ >+ if (if_is_up) >+ sifdown(0); >+ if (ifaddrs[0]) >+ cifaddr(0, ifaddrs[0], ifaddrs[1]); >+ if (default_route_gateway) >+ cifdefaultroute(0, 0, default_route_gateway); >+ if (proxy_arp_addr) >+ cifproxyarp(0, proxy_arp_addr); >+} >+ >+/* >+ * sys_close - Clean up in a child process before execing. >+ */ >+void >+sys_close() >+{ >+ close(iffd); >+ close(pppfd); >+ close(sockfd); >+ closelog(); >+} >+ >+/* >+ * sys_check_options - check the options that the user specified >+ */ >+void >+sys_check_options() >+{ >+} >+ >+ >+/* >+ * daemon - Detach us from controlling terminal session. >+ */ >+int >+daemon(nochdir, noclose) >+ int nochdir, noclose; >+{ >+ int pid; >+ >+ if ((pid = fork()) < 0) >+ return -1; >+ if (pid != 0) >+ exit(0); /* parent dies */ >+ setsid(); >+ if (!nochdir) >+ chdir("/"); >+ if (!noclose) { >+ fclose(stdin); /* don't need stdin, stdout, stderr */ >+ fclose(stdout); >+ fclose(stderr); >+ } >+ return 0; >+} >+ >+/* >+ * note_debug_level - note a change in the debug level. >+ */ >+void >+note_debug_level() >+{ >+ if (debug) { >+ setlogmask(LOG_UPTO(LOG_DEBUG)); >+ } else { >+ setlogmask(LOG_UPTO(LOG_WARNING)); >+ } >+} >+ >+/* >+ * ppp_available - check whether the system has any ppp interfaces >+ */ >+int >+ppp_available() >+{ >+ struct stat buf; >+ >+ return stat("/dev/streams/ppp", &buf) >= 0; >+} >+ >+char pipename[] = "/dev/streams/pipe"; >+ >+/* >+ * streampipe -- Opens a STREAMS based pipe. Used by streamify(). >+ */ >+ >+int >+streampipe(int fd[2]) >+{ >+ if ((fd[0]=open(pipename, O_RDWR)) == -1) >+ return(-1); >+ else if ((fd[1]=open(pipename, O_RDWR)) == -1) { >+ close(fd[0]); >+ return(-1); >+ } else if (ioctl(fd[0], I_PIPE, fd[1]) != 0) { >+ close(fd[0]); >+ close(fd[1]); >+ return(-1); >+ } else { >+ return(ioctl(fd[0], I_PUSH, "pipemod")); >+ } >+} >+ >+/* >+ * streamify -- Needed for Digital UNIX, since some tty devices are not STREAMS >+ * modules (but ptys are, and pipes can be). >+ */ >+ >+#define BUFFSIZE 1000 /* Size of buffer for streamify() */ >+ >+int >+streamify(int fd) >+{ >+ int fdes[2]; >+ fd_set readfds; >+ int ret, fret, rret, maxfd; >+ static char buffer[BUFFSIZE]; >+ struct sigaction sa; >+ >+ if (streampipe(fdes) != 0) >+ syslog(LOG_ERR, "streampipe(): %m\n"); >+ else if (isastream(fdes[0]) == 1) { >+ if ((fret=fork()) < 0) { >+ syslog(LOG_ERR, "fork(): %m\n"); >+ } else if (fret == 0) { >+ /* Process to forward things from pipe to tty */ >+ sigemptyset(&(sa.sa_mask)); >+ sa.sa_handler = SIG_DFL; >+ sa.sa_flags = 0; >+ sigaction(SIGHUP, &sa, NULL); /* Go back to default actions */ >+ sigaction(SIGINT, &sa, NULL); /* for changed signals. */ >+ sigaction(SIGTERM, &sa, NULL); >+ sigaction(SIGCHLD, &sa, NULL); >+ sigaction(SIGUSR1, &sa, NULL); >+ sigaction(SIGUSR2, &sa, NULL); >+ close(fdes[0]); >+ >+ maxfd = (fdes[1]>fd)?fdes[1]:fd; >+ while (1) { >+ FD_ZERO(&readfds); >+ FD_SET(fdes[1], &readfds); >+ FD_SET(fd, &readfds); >+ ret = select(maxfd+1, &readfds, NULL, NULL, NULL); >+ if (FD_ISSET(fd, &readfds)) { >+ rret = read(fd, buffer, BUFFSIZE); >+ if (rret == 0) { >+ MAINDEBUG((LOG_DEBUG, "slave died: EOF on tty.")); >+ exit(0); >+ } else { >+ write(fdes[1], buffer, rret); >+ } >+ } >+ if (FD_ISSET(fdes[1], &readfds)) { >+ rret = read(fdes[1], buffer, BUFFSIZE); >+ if (rret == 0) { >+ MAINDEBUG((LOG_DEBUG, "slave died: EOF on pipe.")); >+ exit(0); >+ } else { >+ write(fd, buffer, rret); >+ } >+ } >+ } >+ } else { >+ close(fdes[1]); >+ orig_ttyfd = fd; >+ return(fdes[0]); >+ } >+ } >+ >+ return(-1); >+} >+ >+/* >+ * establish_ppp - Turn the serial port into a ppp interface. >+ */ >+void >+establish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ if (isastream(fd) != 1) { >+ if ((ttyfd = fd = streamify(fd)) < 0) { >+ syslog(LOG_ERR, "Couldn't get a STREAMS module!\n"); >+ die(1); >+ } >+ } >+ >+ /* Pop any existing modules off the tty stream. */ >+ for (i = 0;; ++i) { >+ if (ioctl(fd, I_LOOK, tty_modules[i]) < 0 >+ || ioctl(fd, I_POP, 0) < 0) >+ break; >+ syslog(LOG_ERR, "popping module %s\n", tty_modules[i]); >+ } >+ >+ tty_nmodules = i; >+ >+ /* Push the async hdlc module and the compressor module. */ >+ if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP Async HDLC module: %m"); >+ die(1); >+ } >+ if (ioctl(fd, I_PUSH, "ppp_comp") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP compression module: %m"); >+/* die(1); */ >+ } >+ >+ /* read mode, message non-discard mode */ >+ if (ioctl(fd, I_SRDOPT, RMSGN|RPROTNORM) < 0) { >+ syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m"); >+ die(1); >+ } >+ >+ /* Link the serial port under the PPP multiplexor. */ >+ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) { >+ syslog(LOG_ERR, "Can't link tty to PPP mux: %m"); >+ die(1); >+ } >+ >+ /* close stdin, stdout, stderr if they might refer to the device */ >+ if (default_device && !closed_stdio) { >+ int i; >+ >+ for (i = 0; i <= 2; ++i) >+ if (i != fd && i != sockfd) >+ close(i); >+ closed_stdio = 1; >+ } >+ >+ /* >+ * Set device for non-blocking reads. >+ */ >+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1 >+ || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { >+ syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m"); >+ } >+} >+ >+/* >+ * restore_loop - reattach the ppp unit to the loopback. >+ * This doesn't need to do anything because disestablish_ppp does it. >+ */ >+void >+restore_loop() >+{ >+} >+ >+/* >+ * disestablish_ppp - Restore the serial port to normal operation. >+ * It attempts to reconstruct the stream with the previously popped >+ * modules. This shouldn't call die() because it's called from die(). >+ */ >+void >+disestablish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ if (fdmuxid >= 0) { >+ if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) { >+ if (!hungup) >+ syslog(LOG_ERR, "Can't unlink tty from PPP mux: %m"); >+ } >+ fdmuxid = -1; >+ >+ /* Reset non-blocking mode on the file descriptor. */ >+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0) >+ syslog(LOG_WARNING, "Couldn't restore device fd flags: %m"); >+ initfdflags = -1; >+ >+ if (!hungup) { >+ while (ioctl(fd, I_POP, 0) >= 0) >+ ; >+ for (i = tty_nmodules - 1; i >= 0; --i) >+ if (ioctl(fd, I_PUSH, tty_modules[i]) < 0) >+ syslog(LOG_ERR, "Couldn't restore tty module %s: %m", >+ tty_modules[i]); >+ } >+ >+ if (hungup && default_device && tty_sid > 0) { >+ /* >+ * If we have received a hangup, we need to send a SIGHUP >+ * to the terminal's controlling process. The reason is >+ * that the original stream head for the terminal hasn't >+ * seen the M_HANGUP message (it went up through the ppp >+ * driver to the stream head for our fd to /dev/ppp). >+ */ >+ syslog(LOG_DEBUG, "sending hangup to %d", tty_sid); >+ if (kill(tty_sid, SIGHUP) < 0) >+ syslog(LOG_ERR, "couldn't kill pgrp: %m"); >+ } >+ if (orig_ttyfd >= 0) { >+ close(fd); >+ (void)wait((void *)0); >+ ttyfd = orig_ttyfd; >+ orig_ttyfd = -1; >+ } >+ } >+} >+ >+/* >+ * Check whether the link seems not to be 8-bit clean. >+ */ >+void >+clean_check() >+{ >+ int x; >+ char *s; >+ >+ if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0) >+ return; >+ s = NULL; >+ switch (~x) { >+ case RCV_B7_0: >+ s = "bit 7 set to 1"; >+ break; >+ case RCV_B7_1: >+ s = "bit 7 set to 0"; >+ break; >+ case RCV_EVNP: >+ s = "odd parity"; >+ break; >+ case RCV_ODDP: >+ s = "even parity"; >+ break; >+ } >+ if (s != NULL) { >+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); >+ syslog(LOG_WARNING, "All received characters had %s", s); >+ } >+} >+ >+/* >+ * List of valid speeds. >+ */ >+struct speed { >+ int speed_int, speed_val; >+} speeds[] = { >+#ifdef B50 >+ { 50, B50 }, >+#endif >+#ifdef B75 >+ { 75, B75 }, >+#endif >+#ifdef B110 >+ { 110, B110 }, >+#endif >+#ifdef B134 >+ { 134, B134 }, >+#endif >+#ifdef B150 >+ { 150, B150 }, >+#endif >+#ifdef B200 >+ { 200, B200 }, >+#endif >+#ifdef B300 >+ { 300, B300 }, >+#endif >+#ifdef B600 >+ { 600, B600 }, >+#endif >+#ifdef B1200 >+ { 1200, B1200 }, >+#endif >+#ifdef B1800 >+ { 1800, B1800 }, >+#endif >+#ifdef B2000 >+ { 2000, B2000 }, >+#endif >+#ifdef B2400 >+ { 2400, B2400 }, >+#endif >+#ifdef B3600 >+ { 3600, B3600 }, >+#endif >+#ifdef B4800 >+ { 4800, B4800 }, >+#endif >+#ifdef B7200 >+ { 7200, B7200 }, >+#endif >+#ifdef B9600 >+ { 9600, B9600 }, >+#endif >+#ifdef B19200 >+ { 19200, B19200 }, >+#endif >+#ifdef B38400 >+ { 38400, B38400 }, >+#endif >+#ifdef EXTA >+ { 19200, EXTA }, >+#endif >+#ifdef EXTB >+ { 38400, EXTB }, >+#endif >+#ifdef B57600 >+ { 57600, B57600 }, >+#endif >+#ifdef B115200 >+ { 115200, B115200 }, >+#endif >+ { 0, 0 } >+}; >+ >+/* >+ * Translate from bits/second to a speed_t. >+ */ >+static int >+translate_speed(bps) >+ int bps; >+{ >+ struct speed *speedp; >+ >+ if (bps == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (bps == speedp->speed_int) >+ return speedp->speed_val; >+ syslog(LOG_WARNING, "speed %d not supported", bps); >+ return 0; >+} >+ >+/* >+ * Translate from a speed_t to bits/second. >+ */ >+static int >+baud_rate_of(speed) >+ int speed; >+{ >+ struct speed *speedp; >+ >+ if (speed == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (speed == speedp->speed_val) >+ return speedp->speed_int; >+ return 0; >+} >+ >+/* >+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, >+ * at the requested speed, etc. If `local' is true, set CLOCAL >+ * regardless of whether the modem option was specified. >+ */ >+void >+set_up_tty(fd, local) >+ int fd, local; >+{ >+ int speed; >+ struct termios tios; >+ >+ if (tcgetattr(fd, &tios) < 0) { >+ syslog(LOG_ERR, "tcgetattr: %m"); >+ die(1); >+ } >+ >+ if (!restore_term) { >+ inittermios = tios; >+ ioctl(fd, TIOCGWINSZ, &wsinfo); >+ } >+ >+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); >+ if (crtscts > 0) >+ tios.c_cflag |= CRTSCTS; >+ else if (crtscts < 0) >+ tios.c_cflag &= ~CRTSCTS; >+ >+ tios.c_cflag |= CS8 | CREAD | HUPCL; >+ if (local || !modem) >+ tios.c_cflag |= CLOCAL; >+ tios.c_iflag = IGNBRK | IGNPAR; >+ tios.c_oflag = 0; >+ tios.c_lflag = 0; >+ tios.c_cc[VMIN] = 1; >+ tios.c_cc[VTIME] = 0; >+ >+ if (crtscts == -2) { >+ tios.c_iflag |= IXON | IXOFF; >+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ >+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ >+ } >+ >+ speed = translate_speed(inspeed); >+ if (speed) { >+ cfsetospeed(&tios, speed); >+ cfsetispeed(&tios, speed); >+ } else { >+ speed = cfgetospeed(&tios); >+ /* >+ * We can't proceed if the serial port speed is 0, >+ * since that implies that the serial port is disabled. >+ */ >+ if (speed == B0) { >+ syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", >+ devnam); >+ die(1); >+ } >+ } >+ >+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { >+ syslog(LOG_ERR, "tcsetattr: %m"); >+ die(1); >+ } >+ >+ baud_rate = inspeed = baud_rate_of(speed); >+ restore_term = 1; >+} >+ >+/* >+ * restore_tty - restore the terminal to the saved settings. >+ */ >+void >+restore_tty(fd) >+ int fd; >+{ >+ if (restore_term) { >+ if (!default_device) { >+ /* >+ * Turn off echoing, because otherwise we can get into >+ * a loop with the tty and the modem echoing to each other. >+ * We presume we are the sole user of this tty device, so >+ * when we close it, it will revert to its defaults anyway. >+ */ >+ inittermios.c_lflag &= ~(ECHO | ECHONL); >+ } >+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) >+ if (!hungup && errno != ENXIO) >+ syslog(LOG_WARNING, "tcsetattr: %m"); >+ ioctl(fd, TIOCSWINSZ, &wsinfo); >+ restore_term = 0; >+ } >+} >+ >+/* >+ * setdtr - control the DTR line on the serial port. >+ * This is called from die(), so it shouldn't call die(). >+ */ >+void >+setdtr(fd, on) >+int fd, on; >+{ >+ int modembits = TIOCM_DTR; >+ >+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); >+} >+ >+/* >+ * open_loopback - open the device we use for getting packets >+ * in demand mode. Under Solaris 2, we use our existing fd >+ * to the ppp driver. >+ */ >+void >+open_ppp_loopback() >+{ >+} >+ >+/* >+ * output - Output PPP packet. >+ */ >+void >+output(unit, p, len) >+ int unit; >+ u_char *p; >+ int len; >+{ >+ struct strbuf data; >+ int retries; >+ struct pollfd pfd; >+ >+ if (debug) >+ log_packet(p, len, "sent ", LOG_DEBUG); >+ >+ data.len = len; >+ data.buf = (caddr_t) p; >+ retries = 4; >+ while (putmsg(pppfd, NULL, &data, 0) < 0) { >+ if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) { >+ if (errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't send packet: %m"); >+ break; >+ } >+ pfd.fd = pppfd; >+ pfd.events = POLLOUT; >+ poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */ >+ } >+} >+ >+ >+/* >+ * wait_input - wait until there is data available on fd, >+ * for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_input(timo) >+ struct timeval *timo; >+{ >+ int t; >+ struct pollfd pfd; >+ >+ t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000; >+ pfd.fd = pppfd; >+ pfd.events = POLLIN | POLLPRI | POLLHUP; >+ if (poll(&pfd, 1, t) < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "poll: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * wait_loop_output - wait until there is data available on the >+ * loopback, for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_loop_output(timo) >+ struct timeval *timo; >+{ >+ wait_input(timo); >+} >+ >+/* >+ * wait_time - wait for a given length of time or until a >+ * signal is received. >+ */ >+void >+wait_time(timo) >+ struct timeval *timo; >+{ >+ int n; >+ >+ n = select(0, NULL, NULL, NULL, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >+ >+ >+/* >+ * read_packet - get a PPP packet from the serial device. >+ */ >+int >+read_packet(buf) >+ u_char *buf; >+{ >+ struct strbuf ctrl, data; >+ int flags, len; >+ unsigned char ctrlbuf[64]; >+ >+ for (;;) { >+ data.maxlen = PPP_MRU + PPP_HDRLEN; >+ data.buf = (caddr_t) buf; >+ ctrl.maxlen = sizeof(ctrlbuf); >+ ctrl.buf = (caddr_t) ctrlbuf; >+ flags = 0; >+ len = getmsg(pppfd, &ctrl, &data, &flags); >+ if (len < 0) { >+ if (errno = EAGAIN || errno == EWOULDBLOCK || errno == EINTR) >+ return -1; >+ syslog(LOG_ERR, "Error reading packet: %m"); >+ die(1); >+ } >+ >+ if (ctrl.len <= 0) >+ return data.len; >+ >+ /* >+ * Got a M_PROTO or M_PCPROTO message. Huh? >+ */ >+ if (debug) >+ syslog(LOG_DEBUG, "got ctrl msg len=%d", ctrl.len); >+ >+ } >+} >+ >+/* >+ * get_loop_output - get outgoing packets from the ppp device, >+ * and detect when we want to bring the real link up. >+ * Return value is 1 if we need to bring up the link, 0 otherwise. >+ */ >+int >+get_loop_output() >+{ >+ int len; >+ int rv = 0; >+ >+ while ((len = read_packet(inpacket_buf)) > 0) { >+ if (loop_frame(inpacket_buf, len)) >+ rv = 1; >+ } >+ return rv; >+} >+ >+/* >+ * ppp_send_config - configure the transmit characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) >+ int unit, mtu; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ >+ link_mtu = mtu; >+ if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MTU: %m"); >+ } >+ if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set transmit ACCM: %m"); >+ } >+ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0); >+ cf[1] = COMP_PROT | COMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC compression: %m"); >+ } >+} >+ >+/* >+ * ppp_set_xaccm - set the extended transmit ACCM for the interface. >+ */ >+void >+ppp_set_xaccm(unit, accm) >+ int unit; >+ ext_accm accm; >+{ >+ if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_WARNING, "Couldn't set extended ACCM: %m"); >+ } >+} >+ >+/* >+ * ppp_recv_config - configure the receive-side characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) >+ int unit, mru; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ >+ link_mru = mru; >+ if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MRU: %m"); >+ } >+ if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set receive ACCM: %m"); >+ } >+ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0); >+ cf[1] = DECOMP_PROT | DECOMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m"); >+ } >+} >+ >+/* >+ * ccp_test - ask kernel whether a given compression method >+ * is acceptable for use. >+ * >+ * In Digital UNIX the memory buckets for chunks >16K are not >+ * primed when the system comes up. That means we're not >+ * likely to get the memory needed for the compressor on >+ * the first try. The way we work around this is to have >+ * the driver spin off a thread to go get the memory for us >+ * (we can't block at that point in a streams context.) >+ * >+ * This code synchronizes with the thread when it has returned >+ * with the memory we need. The driver will continue to return >+ * with EAGAIN until the thread comes back. We give up here >+ * if after 10 attempts in one second we still don't have memory. >+ * It's up to the driver to not lose track of that memory if >+ * thread takes too long to return. >+ */ >+int >+ccp_test(unit, opt_ptr, opt_len, for_transmit) >+ int unit, opt_len, for_transmit; >+ u_char *opt_ptr; >+{ >+ struct timeval tval; >+ int i; >+ >+ tval.tv_sec = 0; >+ tval.tv_usec = 100000; >+ for (i = 0; i < 10; ++i) { >+ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP), >+ opt_ptr, opt_len, 0) >= 0) { >+ return 1; >+ } >+ if (errno != EAGAIN) >+ break; >+ wait_time(&tval); >+ } >+ if (errno != 0) >+ syslog(LOG_ERR, "hard failure trying to get memory for a compressor: %m"); >+ return (errno == ENOSR)? 0: -1; >+} >+ >+/* >+ * ccp_flags_set - inform kernel about the current state of CCP. >+ */ >+void >+ccp_flags_set(unit, isopen, isup) >+ int unit, isopen, isup; >+{ >+ int cf[2]; >+ >+ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0); >+ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't set kernel CCP state: %m"); >+ } >+} >+ >+/* >+ * get_idle_time - return how long the link has been idle. >+ */ >+int >+get_idle_time(u, ip) >+ int u; >+ struct ppp_idle *ip; >+{ >+ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0; >+} >+ >+ >+/* >+ * ccp_fatal_error - returns 1 if decompression was disabled as a >+ * result of an error detected after decompression of a packet, >+ * 0 otherwise. This is necessary because of patent nonsense. >+ */ >+int >+ccp_fatal_error(unit) >+ int unit; >+{ >+ int cf[2]; >+ >+ cf[0] = cf[1] = 0; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (errno != ENXIO && errno != EINVAL) >+ syslog(LOG_ERR, "Couldn't get compression flags: %m"); >+ return 0; >+ } >+ return cf[0] & CCP_FATALERROR; >+} >+ >+/* >+ * sifvjcomp - config tcp header compression >+ */ >+int >+sifvjcomp(u, vjcomp, xcidcomp, xmaxcid) >+ int u, vjcomp, xcidcomp, xmaxcid; >+{ >+ int cf[2]; >+ char maxcid[2]; >+ >+ if (vjcomp) { >+ maxcid[0] = xcidcomp; >+ maxcid[1] = 15; /* XXX should be rmaxcid */ >+ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't initialize VJ compression: %m"); >+ } >+ } >+ >+ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */ >+ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0); >+ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (vjcomp) >+ syslog(LOG_ERR, "Couldn't enable VJ compression: %m"); >+ } >+ >+ return 1; >+} >+ >+/* >+ * sifup - Config the interface up and enable IP packets to pass. >+ */ >+int >+sifup(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (get): %m"); >+ return 0; >+ } >+ ifr.ifr_flags |= IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (set): %m"); >+ return 0; >+ } >+ if_is_up = 1; >+ return 1; >+} >+ >+/* >+ * sifdown - Config the interface down and disable IP. >+ */ >+int >+sifdown(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (get): %m"); >+ return 0; >+ } >+ if ((ifr.ifr_flags & IFF_UP) != 0) { >+ ifr.ifr_flags &= ~IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (set): %m"); >+ return 0; >+ } >+ } >+ if_is_up = 0; >+ return 1; >+} >+ >+/* >+ * sifnpmode - Set the mode for handling packets for a given NP. >+ */ >+int >+sifnpmode(u, proto, mode) >+ int u; >+ int proto; >+ enum NPmode mode; >+{ >+ int npi[2]; >+ >+ npi[0] = proto; >+ npi[1] = (int) mode; >+ if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode); >+ return 0; >+ } >+ return 1; >+} >+ >+#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr) >+ >+/* >+ * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field. >+ */ >+#define SET_SA_FAMILY(addr, family) \ >+ BZERO((char *) &(addr), sizeof(addr)); \ >+ addr.sa_family = (family); \ >+ addr.sa_len = sizeof ((addr)) >+ >+/* >+ * sifaddr - Config the interface IP addresses and netmask. >+ */ >+int >+sifaddr(u, o, h, m) >+ int u; >+ u_int32_t o, h, m; >+{ >+ struct ifreq ifr; >+ struct ifaliasreq addreq; >+ int ret; >+ >+ ret = 1; >+ >+ /* flush old address, if any >+ */ >+ bzero(&ifr, sizeof (ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); >+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET); >+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; >+ if ((ioctl(sockfd, (int)SIOCDIFADDR, (caddr_t) &ifr) < 0) >+ && errno != EADDRNOTAVAIL) { >+ syslog(LOG_ERR, "ioctl(SIOCDIFADDR): %m"); >+ ret = 0; >+ } >+ >+ bzero(&addreq, sizeof (addreq)); >+ strncpy(addreq.ifra_name, ifname, sizeof (addreq.ifra_name)); >+ SET_SA_FAMILY(addreq.ifra_addr, AF_INET); >+ SET_SA_FAMILY(addreq.ifra_broadaddr, AF_INET); >+ ((struct sockaddr_in *)&addreq.ifra_addr)->sin_addr.s_addr = o; >+ ((struct sockaddr_in *)&addreq.ifra_broadaddr)->sin_addr.s_addr = h; >+ >+ if (m != 0) { >+ ((struct sockaddr_in *)&addreq.ifra_mask)->sin_addr.s_addr = m; >+ addreq.ifra_mask.sa_len = sizeof (struct sockaddr); >+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); >+ } >+ >+ /* install new src/dst and (possibly) netmask >+ */ >+ if (ioctl(sockfd, SIOCPIFADDR, &addreq) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCPIFADDR): %m"); >+ ret = 0; >+ } >+ >+ ifr.ifr_metric = link_mtu; >+ if (ioctl(sockfd, SIOCSIPMTU, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP MTU: %m"); >+ ret = 0; >+ } >+ >+ ifaddrs[0] = o; >+ ifaddrs[1] = h; >+ return (ret); >+} >+ >+ >+/* >+ * cifaddr - Clear the interface IP addresses, and delete routes >+ * through the interface if possible. >+ */ >+int >+cifaddr(u, o, h) >+ int u; >+ u_int32_t o, h; >+{ >+ struct ifreq ifr; >+ >+ ifaddrs[0] = 0; >+ bzero(&ifr, sizeof (ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); >+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET); >+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; >+ if (ioctl(sockfd, (int)SIOCDIFADDR, (caddr_t) &ifr) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCDIFADDR): %m"); >+ return 0; >+ } >+ return 1; >+} >+ >+ >+/* >+ * sifdefaultroute - assign a default route through the address given. >+ */ >+int >+sifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct ortentry rt; >+ >+ BZERO(&rt, sizeof(rt)); >+ SET_SA_FAMILY(rt.rt_dst, AF_INET); >+ SET_SA_FAMILY(rt.rt_gateway, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; >+ rt.rt_flags = RTF_GATEWAY; >+ if (ioctl(sockfd, (int)SIOCADDRT, &rt) < 0) { >+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m"); >+ return 0; >+ } >+ default_route_gateway = g; >+ return 1; >+} >+ >+ >+/* >+ * cifdefaultroute - delete a default route through the address given. >+ */ >+int >+cifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct ortentry rt; >+ >+ BZERO(&rt, sizeof(rt)); >+ SET_SA_FAMILY(rt.rt_dst, AF_INET); >+ SET_SA_FAMILY(rt.rt_gateway, AF_INET); >+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; >+ rt.rt_flags = RTF_GATEWAY; >+ if (ioctl(sockfd, (int)SIOCDELRT, &rt) < 0) { >+ syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m"); >+ return 0; >+ } >+ default_route_gateway = 0; >+ return 1; >+} >+ >+/* >+ * sifproxyarp - Make a proxy ARP entry for the peer. >+ */ >+int >+sifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ BZERO(&arpreq, sizeof(arpreq)); >+ >+ /* >+ * Get the hardware address of an interface on the same subnet >+ * as our local address. >+ */ >+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) { >+ syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP"); >+ return 0; >+ } >+ >+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET); >+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; >+ arpreq.arp_flags = ATF_PERM | ATF_PUBL; >+ if (ioctl(sockfd, (int)SIOCSARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = hisaddr; >+ return 1; >+} >+ >+ >+/* >+ * cifproxyarp - Delete the proxy ARP entry for the peer. >+ */ >+int >+cifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ BZERO(&arpreq, sizeof(arpreq)); >+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET); >+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; >+ if (ioctl(sockfd, (int)SIOCDARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCDARP): %m"); >+ return 0; >+ } >+ proxy_arp_addr = 0; >+ return 1; >+} >+ >+/* >+ * get_ether_addr - get the hardware address of an interface on the >+ * the same subnet as ipaddr. >+ */ >+#define MAX_IFS 32 >+ >+static int >+get_ether_addr(ipaddr, hwaddr) >+ u_int32_t ipaddr; >+ struct sockaddr *hwaddr; >+{ >+ struct ifreq *ifr, *ifend; >+ u_int32_t ina, mask; >+ struct ifreq ifreq; >+ struct ifconf ifc; >+ struct ifreq ifs[MAX_IFS]; >+ struct ifdevea ifdevreq; >+ >+ ifc.ifc_len = sizeof(ifs); >+ ifc.ifc_req = ifs; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m"); >+ return 0; >+ } >+ >+ /* >+ * Scan through looking for an interface with an Internet >+ * address on the same subnet as `ipaddr'. >+ */ >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { >+ if (ifr->ifr_addr.sa_family == AF_INET) { >+ >+ /* >+ * Check that the interface is up, and not point-to-point >+ * or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & >+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) >+ != (IFF_UP|IFF_BROADCAST)) >+ continue; >+ >+ /* >+ * Get its netmask and check that it's on the right subnet. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; >+ mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; >+ if ((ipaddr & mask) != (ina & mask)) >+ continue; >+ >+ break; >+ } else { >+ if (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr)) >+ ifr = (struct ifreq *)((caddr_t)ifr + (ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr))); >+ } >+ } >+ >+ if (ifr >= ifend) >+ return 0; >+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name); >+ >+ strncpy(ifdevreq.ifr_name, ifr->ifr_name, sizeof(ifdevreq.ifr_name)); >+ >+ if (ioctl(sockfd, (int)SIOCRPHYSADDR, &ifdevreq) < 0) { >+ perror("ioctl(SIOCRPHYSADDR)"); >+ return(0); >+ } >+ >+ hwaddr->sa_family = AF_UNSPEC; >+ memcpy(hwaddr->sa_data, ifdevreq.current_pa, sizeof(ifdevreq.current_pa)); >+ return 1; >+} >+ >+#define WTMPFILE "/usr/adm/wtmp" >+ >+void >+logwtmp(line, name, host) >+ const char *line, *name, *host; >+{ >+ int fd; >+ struct stat buf; >+ struct utmp ut; >+ >+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) >+ return; >+ if (!fstat(fd, &buf)) { >+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); >+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); >+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); >+ (void)time(&ut.ut_time); >+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) >+ (void)ftruncate(fd, buf.st_size); >+ } >+ close(fd); >+} >+ >+/* >+ * Return user specified netmask, modified by any mask we might determine >+ * for address `addr' (in network byte order). >+ * Here we scan through the system's list of interfaces, looking for >+ * any non-point-to-point interfaces which might appear to be on the same >+ * network as `addr'. If we find any, we OR in their netmask to the >+ * user-specified netmask. >+ */ >+u_int32_t >+GetMask(addr) >+ u_int32_t addr; >+{ >+ u_int32_t mask, nmask, ina; >+ struct ifreq *ifr, *ifend, ifreq; >+ struct ifconf ifc; >+ >+ addr = ntohl(addr); >+ if (IN_CLASSA(addr)) /* determine network mask for address class */ >+ nmask = IN_CLASSA_NET; >+ else if (IN_CLASSB(addr)) >+ nmask = IN_CLASSB_NET; >+ else >+ nmask = IN_CLASSC_NET; >+ /* class D nets are disallowed by bad_ip_adrs */ >+ mask = netmask | htonl(nmask); >+ >+ /* >+ * Scan through the system's network interfaces. >+ */ >+ ifc.ifc_len = MAX_IFS * sizeof(struct ifreq); >+ ifc.ifc_req = (struct ifreq *)alloca(ifc.ifc_len); >+ if (ifc.ifc_req == 0) >+ return mask; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_WARNING, "Couldn't get system interface list: %m"); >+ return mask; >+ } >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { >+ /* >+ * Check the interface's internet address. >+ */ >+ if (ifr->ifr_addr.sa_family == AF_INET) { >+ ina = INET_ADDR(ifr->ifr_addr); >+ if ((ntohl(ina) & nmask) != (addr & nmask)) >+ continue; >+ /* >+ * Check that the interface is up, and not point-to-point or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) >+ != IFF_UP) >+ continue; >+ /* >+ * Get its netmask and OR it into our mask. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ mask |= INET_ADDR(ifreq.ifr_addr); >+ break; >+ } else { >+ if (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr)) >+ ifr = (struct ifreq *)((caddr_t)ifr + (ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr))); >+ } >+ } >+ >+ return mask; >+} >+ >+static int >+strioctl(fd, cmd, ptr, ilen, olen) >+ int fd, cmd, ilen, olen; >+ void *ptr; >+{ >+ struct strioctl str; >+ >+ str.ic_cmd = cmd; >+ str.ic_timout = 0; >+ str.ic_len = ilen; >+ str.ic_dp = ptr; >+ if (ioctl(fd, I_STR, &str) == -1) >+ return -1; >+ if (str.ic_len != olen) >+ syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n", >+ olen, str.ic_len, cmd); >+ return 0; >+} >+ >+/* >+ * Use the hostid as part of the random number seed. >+ */ >+int >+get_host_seed() >+{ >+ return gethostid(); >+} >+ >+/* >+ * Code for locking/unlocking the serial device. >+ * This code is derived from chat.c. >+ */ >+ >+#if !defined(HDB) && !defined(SUNOS3) >+#define HDB 1 /* ascii lock files are the default */ >+#endif >+ >+#ifndef LOCK_DIR >+# if HDB >+# define PIDSTRING >+# define LOCK_PREFIX "/usr/spool/locks/LCK.." >+# else /* HDB */ >+# define LOCK_PREFIX "/usr/spool/uucp/LCK.." >+# endif /* HDB */ >+#endif /* LOCK_DIR */ >+ >+static char *lock_file; /* name of lock file created */ >+ >+/* >+ * lock - create a lock file for the named device. >+ */ >+int >+lock(dev) >+ char *dev; >+{ >+ char hdb_lock_buffer[12]; >+ int fd, pid, n; >+ char *p; >+ >+ if ((p = strrchr(dev, '/')) != NULL) >+ dev = p + 1; >+ lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); >+ if (lock_file == NULL) >+ novm("lock file name"); >+ strcat(strcpy(lock_file, LOCK_PREFIX), dev); >+ >+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { >+ if (errno == EEXIST >+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { >+ /* Read the lock file to find out who has the device locked */ >+#ifdef PIDSTRING >+ n = read(fd, hdb_lock_buffer, 11); >+ if (n > 0) { >+ hdb_lock_buffer[n] = 0; >+ pid = atoi(hdb_lock_buffer); >+ } >+#else >+ n = read(fd, &pid, sizeof(pid)); >+#endif >+ if (n <= 0) { >+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); >+ close(fd); >+ } else { >+ if (kill(pid, 0) == -1 && errno == ESRCH) { >+ /* pid no longer exists - remove the lock file */ >+ if (unlink(lock_file) == 0) { >+ close(fd); >+ syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", >+ dev, pid); >+ continue; >+ } else >+ syslog(LOG_WARNING, "Couldn't remove stale lock on %s", >+ dev); >+ } else >+ syslog(LOG_NOTICE, "Device %s is locked by pid %d", >+ dev, pid); >+ } >+ close(fd); >+ } else >+ syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ return -1; >+ } >+ >+#ifdef PIDSTRING >+ sprintf(hdb_lock_buffer, "%10d\n", getpid()); >+ write(fd, hdb_lock_buffer, 11); >+#else >+ pid = getpid(); >+ write(fd, &pid, sizeof pid); >+#endif >+ >+ close(fd); >+ return 0; >+} >+ >+/* >+ * unlock - remove our lockfile >+ */ >+void >+unlock() >+{ >+ if (lock_file) { >+ unlink(lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ } >+} >+ >+int >+set_filters(pass, active) >+ struct bpf_program *pass, *active; >+{ >+ return 1; >+} >+ >+int >+bpf_compile(program, buf, optimize) >+ struct bpf_program *program; >+ char *buf; >+ int optimize; >+{ >+ return 0; >+} >+ >+char * >+bpf_geterr() >+{ >+ return 0; >+} >+ >+u_int >+bpf_filter(pc, p, wirelen, buflen) >+ struct bpf_insn *pc; >+ u_char *p; >+ u_int wirelen; >+ u_int buflen; >+{ >+ return 0; >+} >diff -rPu pppd.old/sys-sunos4.c pppd/sys-sunos4.c >--- pppd.old/sys-sunos4.c Thu Jan 1 03:00:00 1970 >+++ pppd/sys-sunos4.c Wed Mar 25 05:19:29 1998 >@@ -0,0 +1,1467 @@ >+/* >+ * System-dependent procedures for pppd under SunOS 4. >+ * >+ * Copyright (c) 1994 The Australian National University. >+ * All rights reserved. >+ * >+ * Permission to use, copy, modify, and distribute this software and its >+ * documentation is hereby granted, provided that the above copyright >+ * notice appears in all copies. This software is provided without any >+ * warranty, express or implied. The Australian National University >+ * makes no representations about the suitability of this software for >+ * any purpose. >+ * >+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY >+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES >+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF >+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY >+ * OF SUCH DAMAGE. >+ * >+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, >+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY >+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS >+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO >+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, >+ * OR MODIFICATIONS. >+ */ >+ >+#ifndef lint >+static char rcsid[] = "$Id: sys-sunos4.c,v 1.9 1998/03/25 02:19:29 paulus Exp $"; >+#endif >+ >+#include <stdio.h> >+#include <stddef.h> >+#include <stdlib.h> >+#include <string.h> >+#include <ctype.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <unistd.h> >+#include <termios.h> >+#include <signal.h> >+#include <malloc.h> >+#include <utmp.h> >+#include <sys/types.h> >+#include <sys/param.h> >+#include <sys/socket.h> >+#include <sys/sockio.h> >+#include <sys/stream.h> >+#include <sys/stropts.h> >+#include <sys/syslog.h> >+#include <sys/stat.h> >+#include <sys/time.h> >+#include <sys/poll.h> >+#include <net/if.h> >+#include <net/if_arp.h> >+#include <net/nit_if.h> >+#include <net/route.h> >+#include <net/ppp_defs.h> >+#include <net/pppio.h> >+#include <netinet/in.h> >+ >+#include "pppd.h" >+ >+#if defined(sun) && defined(sparc) >+#include <alloca.h> >+#ifndef __GNUC__ >+extern void *alloca(); >+#endif >+#endif /*sparc*/ >+ >+static int pppfd; >+static int fdmuxid = -1; >+static int iffd; >+static int sockfd; >+ >+static int restore_term; >+static struct termios inittermios; >+static struct winsize wsinfo; /* Initial window size info */ >+static pid_t parent_pid; /* PID of our parent */ >+ >+extern u_char inpacket_buf[]; /* borrowed from main.c */ >+ >+static int link_mtu, link_mru; >+ >+#define NMODULES 32 >+static int tty_nmodules; >+static char tty_modules[NMODULES][FMNAMESZ+1]; >+ >+static int if_is_up; /* Interface has been marked up */ >+static u_int32_t ifaddrs[2]; /* local and remote addresses */ >+static u_int32_t default_route_gateway; /* Gateway for default route added */ >+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ >+ >+/* Prototypes for procedures local to this file. */ >+static int translate_speed __P((int)); >+static int baud_rate_of __P((int)); >+static int get_ether_addr __P((u_int32_t, struct sockaddr *)); >+static int strioctl __P((int, int, void *, int, int)); >+ >+ >+/* >+ * sys_init - System-dependent initialization. >+ */ >+void >+sys_init() >+{ >+ int x; >+ >+ /* Get an internet socket for doing socket ioctl's on. */ >+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { >+ syslog(LOG_ERR, "Couldn't create IP socket: %m"); >+ die(1); >+ } >+ >+ /* >+ * We may want to send a SIGHUP to the session leader associated >+ * with our controlling terminal later. Because SunOS doesn't >+ * have getsid(), we make do with sending the signal to our >+ * parent process. >+ */ >+ parent_pid = getppid(); >+ >+ /* >+ * Open the ppp device. >+ */ >+ pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0); >+ if (pppfd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/ppp: %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ >+ /* Assign a new PPA and get its unit number. */ >+ if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Can't create new PPP interface: %m"); >+ die(1); >+ } >+ >+ /* >+ * Open the ppp device again and push the if_ppp module on it. >+ */ >+ iffd = open("/dev/ppp", O_RDWR, 0); >+ if (iffd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/ppp (2): %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't attach ppp interface to device: %m"); >+ die(1); >+ } >+ if (ioctl(iffd, I_PUSH, "if_ppp") < 0) { >+ syslog(LOG_ERR, "Can't push ppp interface module: %m"); >+ die(1); >+ } >+ if (kdebugflag) { >+ x = PPPDBG_LOG + PPPDBG_IF; >+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't create ppp interface unit: %m"); >+ die(1); >+ } >+ x = PPP_IP; >+ if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't bind ppp interface to IP SAP: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * sys_cleanup - restore any system state we modified before exiting: >+ * mark the interface down, delete default route and/or proxy arp entry. >+ * This shouldn't call die() because it's called from die(). >+ */ >+void >+sys_cleanup() >+{ >+ if (if_is_up) >+ sifdown(0); >+ if (ifaddrs[0]) >+ cifaddr(0, ifaddrs[0], ifaddrs[1]); >+ if (default_route_gateway) >+ cifdefaultroute(0, 0, default_route_gateway); >+ if (proxy_arp_addr) >+ cifproxyarp(0, proxy_arp_addr); >+} >+ >+/* >+ * sys_close - Clean up in a child process before execing. >+ */ >+void >+sys_close() >+{ >+ close(iffd); >+ close(pppfd); >+ close(sockfd); >+} >+ >+/* >+ * sys_check_options - check the options that the user specified >+ */ >+void >+sys_check_options() >+{ >+} >+ >+ >+/* >+ * daemon - Detach us from controlling terminal session. >+ */ >+int >+daemon(nochdir, noclose) >+ int nochdir, noclose; >+{ >+ int pid; >+ >+ if ((pid = fork()) < 0) >+ return -1; >+ if (pid != 0) >+ exit(0); /* parent dies */ >+ setsid(); >+ if (!nochdir) >+ chdir("/"); >+ if (!noclose) { >+ fclose(stdin); /* don't need stdin, stdout, stderr */ >+ fclose(stdout); >+ fclose(stderr); >+ } >+ return 0; >+} >+ >+/* >+ * ppp_available - check whether the system has any ppp interfaces >+ */ >+int >+ppp_available() >+{ >+ struct stat buf; >+ >+ return stat("/dev/ppp", &buf) >= 0; >+} >+ >+/* >+ * establish_ppp - Turn the serial port into a ppp interface. >+ */ >+void >+establish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ /* Pop any existing modules off the tty stream. */ >+ for (i = 0;; ++i) >+ if (ioctl(fd, I_LOOK, tty_modules[i]) < 0 >+ || ioctl(fd, I_POP, 0) < 0) >+ break; >+ tty_nmodules = i; >+ >+ /* Push the async hdlc module and the compressor module. */ >+ if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP Async HDLC module: %m"); >+ die(1); >+ } >+ if (ioctl(fd, I_PUSH, "ppp_comp") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP compression module: %m"); >+/* die(1); */ >+ } >+ >+ /* Link the serial port under the PPP multiplexor. */ >+ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) { >+ syslog(LOG_ERR, "Can't link tty to PPP mux: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * restore_loop - reattach the ppp unit to the loopback. >+ * This doesn't need to do anything because disestablish_ppp does it. >+ */ >+void >+restore_loop() >+{ >+} >+ >+/* >+ * disestablish_ppp - Restore the serial port to normal operation. >+ * It attempts to reconstruct the stream with the previously popped >+ * modules. This shouldn't call die() because it's called from die(). >+ */ >+void >+disestablish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ if (fdmuxid >= 0) { >+ if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) { >+ if (!hungup) >+ syslog(LOG_ERR, "Can't unlink tty from PPP mux: %m"); >+ } >+ fdmuxid = -1; >+ >+ if (!hungup) { >+ while (ioctl(fd, I_POP, 0) >= 0) >+ ; >+ for (i = tty_nmodules - 1; i >= 0; --i) >+ if (ioctl(fd, I_PUSH, tty_modules[i]) < 0) >+ syslog(LOG_ERR, "Couldn't restore tty module %s: %m", >+ tty_modules[i]); >+ } >+ if (hungup && default_device && parent_pid > 0) { >+ /* >+ * If we have received a hangup, we need to send a SIGHUP >+ * to the terminal's controlling process. The reason is >+ * that the original stream head for the terminal hasn't >+ * seen the M_HANGUP message (it went up through the ppp >+ * driver to the stream head for our fd to /dev/ppp). >+ * Actually we send the signal to the process that invoked >+ * pppd, since SunOS doesn't have getsid(). >+ */ >+ kill(parent_pid, SIGHUP); >+ } >+ } >+} >+ >+/* >+ * Check whether the link seems not to be 8-bit clean. >+ */ >+void >+clean_check() >+{ >+ int x; >+ char *s; >+ >+ if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0) >+ return; >+ s = NULL; >+ switch (~x) { >+ case RCV_B7_0: >+ s = "bit 7 set to 1"; >+ break; >+ case RCV_B7_1: >+ s = "bit 7 set to 0"; >+ break; >+ case RCV_EVNP: >+ s = "odd parity"; >+ break; >+ case RCV_ODDP: >+ s = "even parity"; >+ break; >+ } >+ if (s != NULL) { >+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); >+ syslog(LOG_WARNING, "All received characters had %s", s); >+ } >+} >+ >+/* >+ * List of valid speeds. >+ */ >+struct speed { >+ int speed_int, speed_val; >+} speeds[] = { >+#ifdef B50 >+ { 50, B50 }, >+#endif >+#ifdef B75 >+ { 75, B75 }, >+#endif >+#ifdef B110 >+ { 110, B110 }, >+#endif >+#ifdef B134 >+ { 134, B134 }, >+#endif >+#ifdef B150 >+ { 150, B150 }, >+#endif >+#ifdef B200 >+ { 200, B200 }, >+#endif >+#ifdef B300 >+ { 300, B300 }, >+#endif >+#ifdef B600 >+ { 600, B600 }, >+#endif >+#ifdef B1200 >+ { 1200, B1200 }, >+#endif >+#ifdef B1800 >+ { 1800, B1800 }, >+#endif >+#ifdef B2000 >+ { 2000, B2000 }, >+#endif >+#ifdef B2400 >+ { 2400, B2400 }, >+#endif >+#ifdef B3600 >+ { 3600, B3600 }, >+#endif >+#ifdef B4800 >+ { 4800, B4800 }, >+#endif >+#ifdef B7200 >+ { 7200, B7200 }, >+#endif >+#ifdef B9600 >+ { 9600, B9600 }, >+#endif >+#ifdef B19200 >+ { 19200, B19200 }, >+#endif >+#ifdef B38400 >+ { 38400, B38400 }, >+#endif >+#ifdef EXTA >+ { 19200, EXTA }, >+#endif >+#ifdef EXTB >+ { 38400, EXTB }, >+#endif >+#ifdef B57600 >+ { 57600, B57600 }, >+#endif >+#ifdef B115200 >+ { 115200, B115200 }, >+#endif >+ { 0, 0 } >+}; >+ >+/* >+ * Translate from bits/second to a speed_t. >+ */ >+static int >+translate_speed(bps) >+ int bps; >+{ >+ struct speed *speedp; >+ >+ if (bps == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (bps == speedp->speed_int) >+ return speedp->speed_val; >+ syslog(LOG_WARNING, "speed %d not supported", bps); >+ return 0; >+} >+ >+/* >+ * Translate from a speed_t to bits/second. >+ */ >+static int >+baud_rate_of(speed) >+ int speed; >+{ >+ struct speed *speedp; >+ >+ if (speed == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (speed == speedp->speed_val) >+ return speedp->speed_int; >+ return 0; >+} >+ >+/* >+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, >+ * at the requested speed, etc. If `local' is true, set CLOCAL >+ * regardless of whether the modem option was specified. >+ */ >+void >+set_up_tty(fd, local) >+ int fd, local; >+{ >+ int speed; >+ struct termios tios; >+ >+ if (tcgetattr(fd, &tios) < 0) { >+ syslog(LOG_ERR, "tcgetattr: %m"); >+ die(1); >+ } >+ >+ if (!restore_term) { >+ inittermios = tios; >+ ioctl(fd, TIOCGWINSZ, &wsinfo); >+ } >+ >+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); >+ if (crtscts > 0) >+ tios.c_cflag |= CRTSCTS; >+ else if (crtscts < 0) >+ tios.c_cflag &= ~CRTSCTS; >+ >+ tios.c_cflag |= CS8 | CREAD | HUPCL; >+ if (local || !modem) >+ tios.c_cflag |= CLOCAL; >+ tios.c_iflag = IGNBRK | IGNPAR; >+ tios.c_oflag = 0; >+ tios.c_lflag = 0; >+ tios.c_cc[VMIN] = 1; >+ tios.c_cc[VTIME] = 0; >+ >+ if (crtscts == -2) { >+ tios.c_iflag |= IXON | IXOFF; >+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ >+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ >+ } >+ >+ speed = translate_speed(inspeed); >+ if (speed) { >+ cfsetospeed(&tios, speed); >+ cfsetispeed(&tios, speed); >+ } else { >+ speed = cfgetospeed(&tios); >+ /* >+ * We can't proceed if the serial port speed is 0, >+ * since that implies that the serial port is disabled. >+ */ >+ if (speed == B0) { >+ syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", >+ devnam); >+ die(1); >+ } >+ } >+ >+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { >+ syslog(LOG_ERR, "tcsetattr: %m"); >+ die(1); >+ } >+ >+ baud_rate = inspeed = baud_rate_of(speed); >+ restore_term = 1; >+} >+ >+/* >+ * restore_tty - restore the terminal to the saved settings. >+ */ >+void >+restore_tty(fd) >+ int fd; >+{ >+ if (restore_term) { >+ if (!default_device) { >+ /* >+ * Turn off echoing, because otherwise we can get into >+ * a loop with the tty and the modem echoing to each other. >+ * We presume we are the sole user of this tty device, so >+ * when we close it, it will revert to its defaults anyway. >+ */ >+ inittermios.c_lflag &= ~(ECHO | ECHONL); >+ } >+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) >+ if (!hungup && errno != ENXIO) >+ syslog(LOG_WARNING, "tcsetattr: %m"); >+ ioctl(fd, TIOCSWINSZ, &wsinfo); >+ restore_term = 0; >+ } >+} >+ >+/* >+ * setdtr - control the DTR line on the serial port. >+ * This is called from die(), so it shouldn't call die(). >+ */ >+void >+setdtr(fd, on) >+int fd, on; >+{ >+ int modembits = TIOCM_DTR; >+ >+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); >+} >+ >+/* >+ * open_loopback - open the device we use for getting packets >+ * in demand mode. Under Solaris 2, we use our existing fd >+ * to the ppp driver. >+ */ >+void >+open_ppp_loopback() >+{ >+} >+ >+/* >+ * output - Output PPP packet. >+ */ >+void >+output(unit, p, len) >+ int unit; >+ u_char *p; >+ int len; >+{ >+ struct strbuf data; >+ int retries; >+ struct pollfd pfd; >+ >+ if (debug) >+ log_packet(p, len, "sent ", LOG_DEBUG); >+ >+ data.len = len; >+ data.buf = (caddr_t) p; >+ retries = 4; >+ while (putmsg(pppfd, NULL, &data, 0) < 0) { >+ if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) { >+ if (errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't send packet: %m"); >+ break; >+ } >+ pfd.fd = pppfd; >+ pfd.events = POLLOUT; >+ poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */ >+ } >+} >+ >+ >+/* >+ * wait_input - wait until there is data available on fd, >+ * for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_input(timo) >+ struct timeval *timo; >+{ >+ int t; >+ struct pollfd pfd; >+ >+ t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000; >+ pfd.fd = pppfd; >+ pfd.events = POLLIN | POLLPRI | POLLHUP; >+ if (poll(&pfd, 1, t) < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "poll: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * wait_loop_output - wait until there is data available on the >+ * loopback, for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_loop_output(timo) >+ struct timeval *timo; >+{ >+ wait_input(timo); >+} >+ >+/* >+ * wait_time - wait for a given length of time or until a >+ * signal is received. >+ */ >+void >+wait_time(timo) >+ struct timeval *timo; >+{ >+ int n; >+ >+ n = select(0, NULL, NULL, NULL, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >+ >+ >+/* >+ * read_packet - get a PPP packet from the serial device. >+ */ >+int >+read_packet(buf) >+ u_char *buf; >+{ >+ struct strbuf ctrl, data; >+ int flags, len; >+ unsigned char ctrlbuf[64]; >+ >+ for (;;) { >+ data.maxlen = PPP_MRU + PPP_HDRLEN; >+ data.buf = (caddr_t) buf; >+ ctrl.maxlen = sizeof(ctrlbuf); >+ ctrl.buf = (caddr_t) ctrlbuf; >+ flags = 0; >+ len = getmsg(pppfd, &ctrl, &data, &flags); >+ if (len < 0) { >+ if (errno = EAGAIN || errno == EINTR) >+ return -1; >+ syslog(LOG_ERR, "Error reading packet: %m"); >+ die(1); >+ } >+ >+ if (ctrl.len <= 0) >+ return data.len; >+ >+ /* >+ * Got a M_PROTO or M_PCPROTO message. Huh? >+ */ >+ if (debug) >+ syslog(LOG_DEBUG, "got ctrl msg len=%d", ctrl.len); >+ >+ } >+} >+ >+/* >+ * get_loop_output - get outgoing packets from the ppp device, >+ * and detect when we want to bring the real link up. >+ * Return value is 1 if we need to bring up the link, 0 otherwise. >+ */ >+int >+get_loop_output() >+{ >+ int len; >+ int rv = 0; >+ >+ while ((len = read_packet(inpacket_buf)) > 0) { >+ if (loop_frame(inpacket_buf, len)) >+ rv = 1; >+ } >+ return rv; >+} >+ >+/* >+ * ppp_send_config - configure the transmit characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) >+ int unit, mtu; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ struct ifreq ifr; >+ >+ link_mtu = mtu; >+ if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MTU: %m"); >+ } >+ if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set transmit ACCM: %m"); >+ } >+ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0); >+ cf[1] = COMP_PROT | COMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC compression: %m"); >+ } >+ >+ /* set mtu for ip as well */ >+ memset(&ifr, 0, sizeof(ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ ifr.ifr_metric = link_mtu; >+ if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP MTU: %m"); >+ } >+} >+ >+/* >+ * ppp_set_xaccm - set the extended transmit ACCM for the interface. >+ */ >+void >+ppp_set_xaccm(unit, accm) >+ int unit; >+ ext_accm accm; >+{ >+ if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_WARNING, "Couldn't set extended ACCM: %m"); >+ } >+} >+ >+/* >+ * ppp_recv_config - configure the receive-side characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) >+ int unit, mru; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ >+ link_mru = mru; >+ if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MRU: %m"); >+ } >+ if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set receive ACCM: %m"); >+ } >+ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0); >+ cf[1] = DECOMP_PROT | DECOMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m"); >+ } >+} >+ >+/* >+ * ccp_test - ask kernel whether a given compression method >+ * is acceptable for use. >+ */ >+int >+ccp_test(unit, opt_ptr, opt_len, for_transmit) >+ int unit, opt_len, for_transmit; >+ u_char *opt_ptr; >+{ >+ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP), >+ opt_ptr, opt_len, 0) >= 0) >+ return 1; >+ return (errno == ENOSR)? 0: -1; >+} >+ >+/* >+ * ccp_flags_set - inform kernel about the current state of CCP. >+ */ >+void >+ccp_flags_set(unit, isopen, isup) >+ int unit, isopen, isup; >+{ >+ int cf[2]; >+ >+ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0); >+ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't set kernel CCP state: %m"); >+ } >+} >+ >+/* >+ * get_idle_time - return how long the link has been idle. >+ */ >+int >+get_idle_time(u, ip) >+ int u; >+ struct ppp_idle *ip; >+{ >+ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0; >+} >+ >+ >+/* >+ * ccp_fatal_error - returns 1 if decompression was disabled as a >+ * result of an error detected after decompression of a packet, >+ * 0 otherwise. This is necessary because of patent nonsense. >+ */ >+int >+ccp_fatal_error(unit) >+ int unit; >+{ >+ int cf[2]; >+ >+ cf[0] = cf[1] = 0; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (errno != ENXIO && errno != EINVAL) >+ syslog(LOG_ERR, "Couldn't get compression flags: %m"); >+ return 0; >+ } >+ return cf[0] & CCP_FATALERROR; >+} >+ >+/* >+ * sifvjcomp - config tcp header compression >+ */ >+int >+sifvjcomp(u, vjcomp, xcidcomp, xmaxcid) >+ int u, vjcomp, xcidcomp, xmaxcid; >+{ >+ int cf[2]; >+ char maxcid[2]; >+ >+ if (vjcomp) { >+ maxcid[0] = xcidcomp; >+ maxcid[1] = 15; /* XXX should be rmaxcid */ >+ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't initialize VJ compression: %m"); >+ } >+ } >+ >+ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */ >+ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0); >+ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (vjcomp) >+ syslog(LOG_ERR, "Couldn't enable VJ compression: %m"); >+ } >+ >+ return 1; >+} >+ >+/* >+ * sifup - Config the interface up and enable IP packets to pass. >+ */ >+int >+sifup(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (get): %m"); >+ return 0; >+ } >+ ifr.ifr_flags |= IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (set): %m"); >+ return 0; >+ } >+ if_is_up = 1; >+ return 1; >+} >+ >+/* >+ * sifdown - Config the interface down and disable IP. >+ */ >+int >+sifdown(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (get): %m"); >+ return 0; >+ } >+ if ((ifr.ifr_flags & IFF_UP) != 0) { >+ ifr.ifr_flags &= ~IFF_UP; >+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (set): %m"); >+ return 0; >+ } >+ } >+ if_is_up = 0; >+ return 1; >+} >+ >+/* >+ * sifnpmode - Set the mode for handling packets for a given NP. >+ */ >+int >+sifnpmode(u, proto, mode) >+ int u; >+ int proto; >+ enum NPmode mode; >+{ >+ int npi[2]; >+ >+ npi[0] = proto; >+ npi[1] = (int) mode; >+ if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode); >+ return 0; >+ } >+ return 1; >+} >+ >+#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr) >+ >+/* >+ * sifaddr - Config the interface IP addresses and netmask. >+ */ >+int >+sifaddr(u, o, h, m) >+ int u; >+ u_int32_t o, h, m; >+{ >+ struct ifreq ifr; >+ >+ memset(&ifr, 0, sizeof(ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ ifr.ifr_addr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_addr) = m; >+ if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP netmask: %m"); >+ } >+ ifr.ifr_addr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_addr) = o; >+ if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set local IP address: %m"); >+ } >+ ifr.ifr_dstaddr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_dstaddr) = h; >+ if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set remote IP address: %m"); >+ } >+#if 0 /* now done in ppp_send_config */ >+ ifr.ifr_metric = link_mtu; >+ if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP MTU: %m"); >+ } >+#endif >+ ifaddrs[0] = o; >+ ifaddrs[1] = h; >+ >+ return 1; >+} >+ >+/* >+ * cifaddr - Clear the interface IP addresses, and delete routes >+ * through the interface if possible. >+ */ >+int >+cifaddr(u, o, h) >+ int u; >+ u_int32_t o, h; >+{ >+ struct rtentry rt; >+ >+ bzero(&rt, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = h; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = o; >+ rt.rt_flags = RTF_HOST; >+ if (ioctl(sockfd, SIOCDELRT, &rt) < 0) >+ syslog(LOG_ERR, "Couldn't delete route through interface: %m"); >+ ifaddrs[0] = 0; >+ return 1; >+} >+ >+/* >+ * sifdefaultroute - assign a default route through the address given. >+ */ >+int >+sifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct rtentry rt; >+ >+ bzero(&rt, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = 0; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = g; >+ rt.rt_flags = RTF_GATEWAY; >+ >+ if (ioctl(sockfd, SIOCADDRT, &rt) < 0) { >+ syslog(LOG_ERR, "Can't add default route: %m"); >+ return 0; >+ } >+ >+ default_route_gateway = g; >+ return 1; >+} >+ >+/* >+ * cifdefaultroute - delete a default route through the address given. >+ */ >+int >+cifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct rtentry rt; >+ >+ bzero(&rt, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = 0; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = g; >+ rt.rt_flags = RTF_GATEWAY; >+ >+ if (ioctl(sockfd, SIOCDELRT, &rt) < 0) { >+ syslog(LOG_ERR, "Can't delete default route: %m"); >+ return 0; >+ } >+ >+ default_route_gateway = 0; >+ return 1; >+} >+ >+/* >+ * sifproxyarp - Make a proxy ARP entry for the peer. >+ */ >+int >+sifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ bzero(&arpreq, sizeof(arpreq)); >+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) >+ return 0; >+ >+ arpreq.arp_pa.sa_family = AF_INET; >+ INET_ADDR(arpreq.arp_pa) = hisaddr; >+ arpreq.arp_flags = ATF_PERM | ATF_PUBL; >+ if (ioctl(sockfd, SIOCSARP, (caddr_t) &arpreq) < 0) { >+ syslog(LOG_ERR, "Couldn't set proxy ARP entry: %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = hisaddr; >+ return 1; >+} >+ >+/* >+ * cifproxyarp - Delete the proxy ARP entry for the peer. >+ */ >+int >+cifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ bzero(&arpreq, sizeof(arpreq)); >+ arpreq.arp_pa.sa_family = AF_INET; >+ INET_ADDR(arpreq.arp_pa) = hisaddr; >+ if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_ERR, "Couldn't delete proxy ARP entry: %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = 0; >+ return 1; >+} >+ >+/* >+ * get_ether_addr - get the hardware address of an interface on the >+ * the same subnet as ipaddr. >+ */ >+#define MAX_IFS 32 >+ >+static int >+get_ether_addr(ipaddr, hwaddr) >+ u_int32_t ipaddr; >+ struct sockaddr *hwaddr; >+{ >+ struct ifreq *ifr, *ifend; >+ u_int32_t ina, mask; >+ struct ifreq ifreq; >+ struct ifconf ifc; >+ struct ifreq ifs[MAX_IFS]; >+ int nit_fd; >+ >+ ifc.ifc_len = sizeof(ifs); >+ ifc.ifc_req = ifs; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m"); >+ return 0; >+ } >+ >+ /* >+ * Scan through looking for an interface with an Internet >+ * address on the same subnet as `ipaddr'. >+ */ >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *) >+ ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) { >+ if (ifr->ifr_addr.sa_family == AF_INET) { >+ >+ /* >+ * Check that the interface is up, and not point-to-point >+ * or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & >+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) >+ != (IFF_UP|IFF_BROADCAST)) >+ continue; >+ >+ /* >+ * Get its netmask and check that it's on the right subnet. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; >+ mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; >+ if ((ipaddr & mask) != (ina & mask)) >+ continue; >+ >+ break; >+ } >+ } >+ >+ if (ifr >= ifend) >+ return 0; >+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name); >+ >+ /* >+ * Grab the physical address for this interface. >+ */ >+ if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) { >+ syslog(LOG_ERR, "Couldn't open /dev/nit: %m"); >+ return 0; >+ } >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0 >+ || ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) { >+ syslog(LOG_ERR, "Couldn't get hardware address for %s: %m", >+ ifreq.ifr_name); >+ close(nit_fd); >+ return 0; >+ } >+ >+ hwaddr->sa_family = AF_UNSPEC; >+ memcpy(hwaddr->sa_data, ifreq.ifr_addr.sa_data, 6); >+ close(nit_fd); >+ return 1; >+} >+ >+#define WTMPFILE "/usr/adm/wtmp" >+ >+void >+logwtmp(line, name, host) >+ const char *line, *name, *host; >+{ >+ int fd; >+ struct stat buf; >+ struct utmp ut; >+ >+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) >+ return; >+ if (!fstat(fd, &buf)) { >+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); >+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); >+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); >+ (void)time(&ut.ut_time); >+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) >+ (void)ftruncate(fd, buf.st_size); >+ } >+ close(fd); >+} >+ >+/* >+ * Return user specified netmask, modified by any mask we might determine >+ * for address `addr' (in network byte order). >+ * Here we scan through the system's list of interfaces, looking for >+ * any non-point-to-point interfaces which might appear to be on the same >+ * network as `addr'. If we find any, we OR in their netmask to the >+ * user-specified netmask. >+ */ >+u_int32_t >+GetMask(addr) >+ u_int32_t addr; >+{ >+ u_int32_t mask, nmask, ina; >+ struct ifreq *ifr, *ifend, ifreq; >+ struct ifconf ifc; >+ >+ addr = ntohl(addr); >+ if (IN_CLASSA(addr)) /* determine network mask for address class */ >+ nmask = IN_CLASSA_NET; >+ else if (IN_CLASSB(addr)) >+ nmask = IN_CLASSB_NET; >+ else >+ nmask = IN_CLASSC_NET; >+ /* class D nets are disallowed by bad_ip_adrs */ >+ mask = netmask | htonl(nmask); >+ >+ /* >+ * Scan through the system's network interfaces. >+ */ >+ ifc.ifc_len = MAX_IFS * sizeof(struct ifreq); >+ ifc.ifc_req = alloca(ifc.ifc_len); >+ if (ifc.ifc_req == 0) >+ return mask; >+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_WARNING, "Couldn't get system interface list: %m"); >+ return mask; >+ } >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) { >+ /* >+ * Check the interface's internet address. >+ */ >+ if (ifr->ifr_addr.sa_family != AF_INET) >+ continue; >+ ina = INET_ADDR(ifr->ifr_addr); >+ if ((ntohl(ina) & nmask) != (addr & nmask)) >+ continue; >+ /* >+ * Check that the interface is up, and not point-to-point or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) >+ != IFF_UP) >+ continue; >+ /* >+ * Get its netmask and OR it into our mask. >+ */ >+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ mask |= INET_ADDR(ifreq.ifr_addr); >+ } >+ >+ return mask; >+} >+ >+static int >+strioctl(fd, cmd, ptr, ilen, olen) >+ int fd, cmd, ilen, olen; >+ void *ptr; >+{ >+ struct strioctl str; >+ >+ str.ic_cmd = cmd; >+ str.ic_timout = 0; >+ str.ic_len = ilen; >+ str.ic_dp = ptr; >+ if (ioctl(fd, I_STR, &str) == -1) >+ return -1; >+ if (str.ic_len != olen) >+ syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n", >+ olen, str.ic_len, cmd); >+ return 0; >+} >+ >+/* >+ * Use the hostid as part of the random number seed. >+ */ >+int >+get_host_seed() >+{ >+ return gethostid(); >+} >+ >+/* >+ * Code for locking/unlocking the serial device. >+ * This code is derived from chat.c. >+ */ >+ >+#if !defined(HDB) && !defined(SUNOS3) >+#define HDB 1 /* ascii lock files are the default */ >+#endif >+ >+#ifndef LOCK_DIR >+# if HDB >+# define PIDSTRING >+# define LOCK_PREFIX "/usr/spool/locks/LCK.." >+# else /* HDB */ >+# define LOCK_PREFIX "/usr/spool/uucp/LCK.." >+# endif /* HDB */ >+#endif /* LOCK_DIR */ >+ >+static char *lock_file; /* name of lock file created */ >+ >+/* >+ * lock - create a lock file for the named device. >+ */ >+int >+lock(dev) >+ char *dev; >+{ >+ char hdb_lock_buffer[12]; >+ int fd, pid, n; >+ char *p; >+ >+ if ((p = strrchr(dev, '/')) != NULL) >+ dev = p + 1; >+ lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); >+ if (lock_file == NULL) >+ novm("lock file name"); >+ strcat(strcpy(lock_file, LOCK_PREFIX), dev); >+ >+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { >+ if (errno == EEXIST >+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { >+ /* Read the lock file to find out who has the device locked */ >+#ifdef PIDSTRING >+ n = read(fd, hdb_lock_buffer, 11); >+ if (n > 0) { >+ hdb_lock_buffer[n] = 0; >+ pid = atoi(hdb_lock_buffer); >+ } >+#else >+ n = read(fd, &pid, sizeof(pid)); >+#endif >+ if (n <= 0) { >+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); >+ close(fd); >+ } else { >+ if (kill(pid, 0) == -1 && errno == ESRCH) { >+ /* pid no longer exists - remove the lock file */ >+ if (unlink(lock_file) == 0) { >+ close(fd); >+ syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", >+ dev, pid); >+ continue; >+ } else >+ syslog(LOG_WARNING, "Couldn't remove stale lock on %s", >+ dev); >+ } else >+ syslog(LOG_NOTICE, "Device %s is locked by pid %d", >+ dev, pid); >+ } >+ close(fd); >+ } else >+ syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ return -1; >+ } >+ >+#ifdef PIDSTRING >+ sprintf(hdb_lock_buffer, "%10d\n", getpid()); >+ write(fd, hdb_lock_buffer, 11); >+#else >+ pid = getpid(); >+ write(fd, &pid, sizeof pid); >+#endif >+ >+ close(fd); >+ return 0; >+} >+ >+/* >+ * unlock - remove our lockfile >+ */ >+void >+unlock() >+{ >+ if (lock_file) { >+ unlink(lock_file); >+ free(lock_file); >+ lock_file = NULL; >+ } >+} >+ >+/* >+ * SunOS doesn't have strtoul :-( >+ */ >+unsigned long >+strtoul(str, ptr, base) >+ char *str, **ptr; >+ int base; >+{ >+ return (unsigned long) strtol(str, ptr, base); >+} >+ >+/* >+ * Or strerror :-( >+ */ >+extern char *sys_errlist[]; >+extern int sys_nerr; >+ >+char * >+strerror(n) >+ int n; >+{ >+ static char unknown[32]; >+ >+ if (n > 0 && n < sys_nerr) >+ return sys_errlist[n]; >+ sprintf(unknown, "Error %d", n); >+ return unknown; >+} >diff -rPu pppd.old/sys-svr4.c pppd/sys-svr4.c >--- pppd.old/sys-svr4.c Thu Jan 1 03:00:00 1970 >+++ pppd/sys-svr4.c Wed Mar 25 05:19:31 1998 >@@ -0,0 +1,1690 @@ >+/* >+ * System-dependent procedures for pppd under Solaris 2. >+ * >+ * Copyright (c) 1994 The Australian National University. >+ * All rights reserved. >+ * >+ * Permission to use, copy, modify, and distribute this software and its >+ * documentation is hereby granted, provided that the above copyright >+ * notice appears in all copies. This software is provided without any >+ * warranty, express or implied. The Australian National University >+ * makes no representations about the suitability of this software for >+ * any purpose. >+ * >+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY >+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES >+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF >+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY >+ * OF SUCH DAMAGE. >+ * >+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, >+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY >+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS >+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO >+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, >+ * OR MODIFICATIONS. >+ */ >+ >+#ifndef lint >+static char rcsid[] = "$Id: sys-svr4.c,v 1.17 1998/03/25 02:19:31 paulus Exp $"; >+#endif >+ >+#include <limits.h> >+#include <stdio.h> >+#include <stddef.h> >+#include <stdlib.h> >+#include <ctype.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <unistd.h> >+#include <termios.h> >+#ifndef CRTSCTS >+#include <sys/termiox.h> >+#endif >+#include <signal.h> >+#include <utmpx.h> >+#include <sys/types.h> >+#include <sys/ioccom.h> >+#include <sys/stream.h> >+#include <sys/stropts.h> >+#include <sys/socket.h> >+#include <sys/sockio.h> >+#include <sys/syslog.h> >+#include <sys/sysmacros.h> >+#include <sys/systeminfo.h> >+#include <sys/dlpi.h> >+#include <sys/stat.h> >+#include <sys/mkdev.h> >+#include <net/if.h> >+#include <net/if_arp.h> >+#include <net/route.h> >+#include <net/ppp_defs.h> >+#include <net/pppio.h> >+#include <netinet/in.h> >+ >+#include "pppd.h" >+ >+static int pppfd; >+static int fdmuxid = -1; >+static int ipfd; >+static int ipmuxid = -1; >+ >+static int restore_term; >+static struct termios inittermios; >+#ifndef CRTSCTS >+static struct termiox inittermiox; >+static int termiox_ok; >+#endif >+static struct winsize wsinfo; /* Initial window size info */ >+static pid_t tty_sid; /* original session ID for terminal */ >+ >+extern u_char inpacket_buf[]; /* borrowed from main.c */ >+ >+static int link_mtu, link_mru; >+ >+#define NMODULES 32 >+static int tty_nmodules; >+static char tty_modules[NMODULES][FMNAMESZ+1]; >+ >+static int if_is_up; /* Interface has been marked up */ >+static u_int32_t default_route_gateway; /* Gateway for default route added */ >+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ >+ >+/* Prototypes for procedures local to this file. */ >+static int translate_speed __P((int)); >+static int baud_rate_of __P((int)); >+static int get_ether_addr __P((u_int32_t, struct sockaddr *)); >+static int get_hw_addr __P((char *, struct sockaddr *)); >+static int dlpi_attach __P((int, int)); >+static int dlpi_info_req __P((int)); >+static int dlpi_get_reply __P((int, union DL_primitives *, int, int)); >+static int strioctl __P((int, int, void *, int, int)); >+ >+ >+/* >+ * sys_init - System-dependent initialization. >+ */ >+void >+sys_init() >+{ >+ int ifd, x; >+#ifndef sun >+ struct ifreq ifr; >+ struct { >+ union DL_primitives prim; >+ char space[64]; >+ } reply; >+#endif >+ >+ ipfd = open("/dev/ip", O_RDWR, 0); >+ if (ipfd < 0) { >+ syslog(LOG_ERR, "Couldn't open IP device: %m"); >+ die(1); >+ } >+ >+ if (default_device) >+ tty_sid = getsid((pid_t)0); >+ >+ pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0); >+ if (pppfd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/ppp: %m"); >+ die(1); >+ } >+ if (kdebugflag & 1) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+ >+ /* Assign a new PPA and get its unit number. */ >+ if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Can't create new PPP interface: %m"); >+ die(1); >+ } >+ >+ /* >+ * Open the ppp device again and link it under the ip multiplexor. >+ * IP will assign a unit number which hopefully is the same as ifunit. >+ * I don't know any way to be certain they will be the same. :-( >+ */ >+ ifd = open("/dev/ppp", O_RDWR, 0); >+ if (ifd < 0) { >+ syslog(LOG_ERR, "Can't open /dev/ppp (2): %m"); >+ die(1); >+ } >+ if (kdebugflag & 1) { >+ x = PPPDBG_LOG + PPPDBG_DRIVER; >+ strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0); >+ } >+#ifdef sun >+ if (ioctl(ifd, I_PUSH, "ip") < 0) { >+ syslog(LOG_ERR, "Can't push IP module: %m"); >+ close(ifd); >+ die(1); >+ } >+#else >+ if (dlpi_attach(ifd, ifunit) < 0 || >+ dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) { >+ syslog(LOG_ERR, "Can't attach to ppp%d: %m", ifunit); >+ close(ifd); >+ die(1); >+ } >+#endif >+ ipmuxid = ioctl(ipfd, I_LINK, ifd); >+ close(ifd); >+ if (ipmuxid < 0) { >+ syslog(LOG_ERR, "Can't link PPP device to IP: %m"); >+ die(1); >+ } >+ >+#ifndef sun >+ /* Set the interface name for the link. */ >+ (void) sprintf (ifr.ifr_name, "ppp%d", ifunit); >+ ifr.ifr_metric = ipmuxid; >+ if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0) { >+ syslog(LOG_ERR, "Can't set interface name %s: %m", ifr.ifr_name); >+ die(1); >+ } >+#endif >+} >+ >+/* >+ * sys_cleanup - restore any system state we modified before exiting: >+ * mark the interface down, delete default route and/or proxy arp entry. >+ * This should call die() because it's called from die(). >+ */ >+void >+sys_cleanup() >+{ >+ struct ifreq ifr; >+ >+ if (if_is_up) >+ sifdown(0); >+ if (default_route_gateway) >+ cifdefaultroute(0, default_route_gateway, default_route_gateway); >+ if (proxy_arp_addr) >+ cifproxyarp(0, proxy_arp_addr); >+} >+ >+/* >+ * sys_close - Clean up in a child process before execing. >+ */ >+void >+sys_close() >+{ >+ close(ipfd); >+ if (pppfd >= 0) >+ close(pppfd); >+} >+ >+/* >+ * sys_check_options - check the options that the user specified >+ */ >+void >+sys_check_options() >+{ >+} >+ >+ >+/* >+ * daemon - Detach us from controlling terminal session. >+ */ >+int >+daemon(nochdir, noclose) >+ int nochdir, noclose; >+{ >+ int pid; >+ >+ if ((pid = fork()) < 0) >+ return -1; >+ if (pid != 0) >+ exit(0); /* parent dies */ >+ setsid(); >+ if (!nochdir) >+ chdir("/"); >+ if (!noclose) { >+ fclose(stdin); /* don't need stdin, stdout, stderr */ >+ fclose(stdout); >+ fclose(stderr); >+ } >+ return 0; >+} >+ >+/* >+ * ppp_available - check whether the system has any ppp interfaces >+ */ >+int >+ppp_available() >+{ >+ struct stat buf; >+ >+ return stat("/dev/ppp", &buf) >= 0; >+} >+ >+/* >+ * establish_ppp - Turn the serial port into a ppp interface. >+ */ >+void >+establish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ /* Pop any existing modules off the tty stream. */ >+ for (i = 0;; ++i) >+ if (ioctl(fd, I_LOOK, tty_modules[i]) < 0 >+ || ioctl(fd, I_POP, 0) < 0) >+ break; >+ tty_nmodules = i; >+ >+ /* Push the async hdlc module and the compressor module. */ >+ if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP Async HDLC module: %m"); >+ die(1); >+ } >+ if (kdebugflag & 4) { >+ i = PPPDBG_LOG + PPPDBG_AHDLC; >+ strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0); >+ } >+ if (ioctl(fd, I_PUSH, "ppp_comp") < 0) { >+ syslog(LOG_ERR, "Couldn't push PPP compression module: %m"); >+/* die(1); */ >+ } >+ if (kdebugflag & 2) { >+ i = PPPDBG_LOG + PPPDBG_COMP; >+ strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0); >+ } >+ >+ /* Link the serial port under the PPP multiplexor. */ >+ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) { >+ syslog(LOG_ERR, "Can't link tty to PPP mux: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * restore_loop - reattach the ppp unit to the loopback. >+ * This doesn't need to do anything because disestablish_ppp does it. >+ */ >+void >+restore_loop() >+{ >+} >+ >+/* >+ * disestablish_ppp - Restore the serial port to normal operation. >+ * It attempts to reconstruct the stream with the previously popped >+ * modules. This shouldn't call die() because it's called from die(). >+ */ >+void >+disestablish_ppp(fd) >+ int fd; >+{ >+ int i; >+ >+ if (fdmuxid >= 0) { >+ if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) { >+ if (!hungup) >+ syslog(LOG_ERR, "Can't unlink tty from PPP mux: %m"); >+ } >+ fdmuxid = -1; >+ >+ if (!hungup) { >+ while (ioctl(fd, I_POP, 0) >= 0) >+ ; >+ for (i = tty_nmodules - 1; i >= 0; --i) >+ if (ioctl(fd, I_PUSH, tty_modules[i]) < 0) >+ syslog(LOG_ERR, "Couldn't restore tty module %s: %m", >+ tty_modules[i]); >+ } >+ if (hungup && default_device && tty_sid > 0) { >+ /* >+ * If we have received a hangup, we need to send a SIGHUP >+ * to the terminal's controlling process. The reason is >+ * that the original stream head for the terminal hasn't >+ * seen the M_HANGUP message (it went up through the ppp >+ * driver to the stream head for our fd to /dev/ppp). >+ */ >+ kill(tty_sid, SIGHUP); >+ } >+ } >+} >+ >+/* >+ * Check whether the link seems not to be 8-bit clean. >+ */ >+void >+clean_check() >+{ >+ int x; >+ char *s; >+ >+ if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0) >+ return; >+ s = NULL; >+ switch (~x) { >+ case RCV_B7_0: >+ s = "bit 7 set to 1"; >+ break; >+ case RCV_B7_1: >+ s = "bit 7 set to 0"; >+ break; >+ case RCV_EVNP: >+ s = "odd parity"; >+ break; >+ case RCV_ODDP: >+ s = "even parity"; >+ break; >+ } >+ if (s != NULL) { >+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); >+ syslog(LOG_WARNING, "All received characters had %s", s); >+ } >+} >+ >+/* >+ * List of valid speeds. >+ */ >+struct speed { >+ int speed_int, speed_val; >+} speeds[] = { >+#ifdef B50 >+ { 50, B50 }, >+#endif >+#ifdef B75 >+ { 75, B75 }, >+#endif >+#ifdef B110 >+ { 110, B110 }, >+#endif >+#ifdef B134 >+ { 134, B134 }, >+#endif >+#ifdef B150 >+ { 150, B150 }, >+#endif >+#ifdef B200 >+ { 200, B200 }, >+#endif >+#ifdef B300 >+ { 300, B300 }, >+#endif >+#ifdef B600 >+ { 600, B600 }, >+#endif >+#ifdef B1200 >+ { 1200, B1200 }, >+#endif >+#ifdef B1800 >+ { 1800, B1800 }, >+#endif >+#ifdef B2000 >+ { 2000, B2000 }, >+#endif >+#ifdef B2400 >+ { 2400, B2400 }, >+#endif >+#ifdef B3600 >+ { 3600, B3600 }, >+#endif >+#ifdef B4800 >+ { 4800, B4800 }, >+#endif >+#ifdef B7200 >+ { 7200, B7200 }, >+#endif >+#ifdef B9600 >+ { 9600, B9600 }, >+#endif >+#ifdef B19200 >+ { 19200, B19200 }, >+#endif >+#ifdef B38400 >+ { 38400, B38400 }, >+#endif >+#ifdef EXTA >+ { 19200, EXTA }, >+#endif >+#ifdef EXTB >+ { 38400, EXTB }, >+#endif >+#ifdef B57600 >+ { 57600, B57600 }, >+#endif >+#ifdef B115200 >+ { 115200, B115200 }, >+#endif >+ { 0, 0 } >+}; >+ >+/* >+ * Translate from bits/second to a speed_t. >+ */ >+static int >+translate_speed(bps) >+ int bps; >+{ >+ struct speed *speedp; >+ >+ if (bps == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (bps == speedp->speed_int) >+ return speedp->speed_val; >+ syslog(LOG_WARNING, "speed %d not supported", bps); >+ return 0; >+} >+ >+/* >+ * Translate from a speed_t to bits/second. >+ */ >+static int >+baud_rate_of(speed) >+ int speed; >+{ >+ struct speed *speedp; >+ >+ if (speed == 0) >+ return 0; >+ for (speedp = speeds; speedp->speed_int; speedp++) >+ if (speed == speedp->speed_val) >+ return speedp->speed_int; >+ return 0; >+} >+ >+/* >+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, >+ * at the requested speed, etc. If `local' is true, set CLOCAL >+ * regardless of whether the modem option was specified. >+ */ >+void >+set_up_tty(fd, local) >+ int fd, local; >+{ >+ int speed; >+ struct termios tios; >+#if !defined (CRTSCTS) >+ struct termiox tiox; >+#endif >+ >+ if (tcgetattr(fd, &tios) < 0) { >+ syslog(LOG_ERR, "tcgetattr: %m"); >+ die(1); >+ } >+ >+#ifndef CRTSCTS >+ termiox_ok = 1; >+ if (ioctl (fd, TCGETX, &tiox) < 0) { >+ termiox_ok = 0; >+ if (errno != ENOTTY) >+ syslog (LOG_ERR, "TCGETX: %m"); >+ } >+#endif >+ >+ if (!restore_term) { >+ inittermios = tios; >+#ifndef CRTSCTS >+ inittermiox = tiox; >+#endif >+ ioctl(fd, TIOCGWINSZ, &wsinfo); >+ } >+ >+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); >+#ifdef CRTSCTS >+ if (crtscts > 0) >+ tios.c_cflag |= CRTSCTS; >+ else if (crtscts < 0) >+ tios.c_cflag &= ~CRTSCTS; >+#else >+ if (crtscts != 0 && !termiox_ok) { >+ syslog(LOG_ERR, "Can't set RTS/CTS flow control"); >+ } else if (crtscts > 0) { >+ tiox.x_hflag |= RTSXOFF|CTSXON; >+ } else if (crtscts < 0) { >+ tiox.x_hflag &= ~(RTSXOFF|CTSXON); >+ } >+#endif >+ >+ tios.c_cflag |= CS8 | CREAD | HUPCL; >+ if (local || !modem) >+ tios.c_cflag |= CLOCAL; >+ tios.c_iflag = IGNBRK | IGNPAR; >+ tios.c_oflag = 0; >+ tios.c_lflag = 0; >+ tios.c_cc[VMIN] = 1; >+ tios.c_cc[VTIME] = 0; >+ >+ if (crtscts == -2) { >+ tios.c_iflag |= IXON | IXOFF; >+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ >+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ >+ } >+ >+ speed = translate_speed(inspeed); >+ if (speed) { >+ cfsetospeed(&tios, speed); >+ cfsetispeed(&tios, speed); >+ } else { >+ speed = cfgetospeed(&tios); >+ /* >+ * We can't proceed if the serial port speed is 0, >+ * since that implies that the serial port is disabled. >+ */ >+ if (speed == B0) { >+ syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", >+ devnam); >+ die(1); >+ } >+ } >+ >+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { >+ syslog(LOG_ERR, "tcsetattr: %m"); >+ die(1); >+ } >+ >+#ifndef CRTSCTS >+ if (termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){ >+ syslog (LOG_ERR, "TCSETXF: %m"); >+ } >+#endif >+ >+ baud_rate = inspeed = baud_rate_of(speed); >+ restore_term = 1; >+} >+ >+/* >+ * restore_tty - restore the terminal to the saved settings. >+ */ >+void >+restore_tty(fd) >+ int fd; >+{ >+ if (restore_term) { >+ if (!default_device) { >+ /* >+ * Turn off echoing, because otherwise we can get into >+ * a loop with the tty and the modem echoing to each other. >+ * We presume we are the sole user of this tty device, so >+ * when we close it, it will revert to its defaults anyway. >+ */ >+ inittermios.c_lflag &= ~(ECHO | ECHONL); >+ } >+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) >+ if (!hungup && errno != ENXIO) >+ syslog(LOG_WARNING, "tcsetattr: %m"); >+#ifndef CRTSCTS >+ if (ioctl (fd, TCSETXF, &inittermiox) < 0){ >+ if (!hungup && errno != ENXIO) >+ syslog (LOG_ERR, "TCSETXF: %m"); >+ } >+#endif >+ ioctl(fd, TIOCSWINSZ, &wsinfo); >+ restore_term = 0; >+ } >+} >+ >+/* >+ * setdtr - control the DTR line on the serial port. >+ * This is called from die(), so it shouldn't call die(). >+ */ >+void >+setdtr(fd, on) >+int fd, on; >+{ >+ int modembits = TIOCM_DTR; >+ >+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); >+} >+ >+/* >+ * open_loopback - open the device we use for getting packets >+ * in demand mode. Under Solaris 2, we use our existing fd >+ * to the ppp driver. >+ */ >+void >+open_ppp_loopback() >+{ >+} >+ >+/* >+ * output - Output PPP packet. >+ */ >+void >+output(unit, p, len) >+ int unit; >+ u_char *p; >+ int len; >+{ >+ struct strbuf data; >+ int retries; >+ struct pollfd pfd; >+ >+ if (debug) >+ log_packet(p, len, "sent ", LOG_DEBUG); >+ >+ data.len = len; >+ data.buf = (caddr_t) p; >+ retries = 4; >+ while (putmsg(pppfd, NULL, &data, 0) < 0) { >+ if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) { >+ if (errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't send packet: %m"); >+ break; >+ } >+ pfd.fd = pppfd; >+ pfd.events = POLLOUT; >+ poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */ >+ } >+} >+ >+ >+/* >+ * wait_input - wait until there is data available on fd, >+ * for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_input(timo) >+ struct timeval *timo; >+{ >+ int t; >+ struct pollfd pfd; >+ >+ t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000; >+ pfd.fd = pppfd; >+ pfd.events = POLLIN | POLLPRI | POLLHUP; >+ if (poll(&pfd, 1, t) < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "poll: %m"); >+ die(1); >+ } >+} >+ >+/* >+ * wait_loop_output - wait until there is data available on the >+ * loopback, for the length of time specified by *timo (indefinite >+ * if timo is NULL). >+ */ >+void >+wait_loop_output(timo) >+ struct timeval *timo; >+{ >+ wait_input(timo); >+} >+ >+/* >+ * wait_time - wait for a given length of time or until a >+ * signal is received. >+ */ >+void >+wait_time(timo) >+ struct timeval *timo; >+{ >+ int n; >+ >+ n = select(0, NULL, NULL, NULL, timo); >+ if (n < 0 && errno != EINTR) { >+ syslog(LOG_ERR, "select: %m"); >+ die(1); >+ } >+} >+ >+ >+/* >+ * read_packet - get a PPP packet from the serial device. >+ */ >+int >+read_packet(buf) >+ u_char *buf; >+{ >+ struct strbuf ctrl, data; >+ int flags, len; >+ unsigned char ctrlbuf[sizeof(union DL_primitives) + 64]; >+ >+ for (;;) { >+ data.maxlen = PPP_MRU + PPP_HDRLEN; >+ data.buf = (caddr_t) buf; >+ ctrl.maxlen = sizeof(ctrlbuf); >+ ctrl.buf = (caddr_t) ctrlbuf; >+ flags = 0; >+ len = getmsg(pppfd, &ctrl, &data, &flags); >+ if (len < 0) { >+ if (errno = EAGAIN || errno == EINTR) >+ return -1; >+ syslog(LOG_ERR, "Error reading packet: %m"); >+ die(1); >+ } >+ >+ if (ctrl.len <= 0) >+ return data.len; >+ >+ /* >+ * Got a M_PROTO or M_PCPROTO message. Interpret it >+ * as a DLPI primitive?? >+ */ >+ if (debug) >+ syslog(LOG_DEBUG, "got dlpi prim 0x%x, len=%d", >+ ((union DL_primitives *)ctrlbuf)->dl_primitive, ctrl.len); >+ >+ } >+} >+ >+/* >+ * get_loop_output - get outgoing packets from the ppp device, >+ * and detect when we want to bring the real link up. >+ * Return value is 1 if we need to bring up the link, 0 otherwise. >+ */ >+int >+get_loop_output() >+{ >+ int len; >+ int rv = 0; >+ >+ while ((len = read_packet(inpacket_buf)) > 0) { >+ if (loop_frame(inpacket_buf, len)) >+ rv = 1; >+ } >+ return rv; >+} >+ >+/* >+ * ppp_send_config - configure the transmit characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) >+ int unit, mtu; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ struct ifreq ifr; >+ >+ link_mtu = mtu; >+ if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MTU: %m"); >+ } >+ if (fdmuxid >= 0) { >+ /* can't set these if we don't have a stream attached below /dev/ppp */ >+ if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set transmit ACCM: %m"); >+ } >+ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0); >+ cf[1] = COMP_PROT | COMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC compression: %m"); >+ } >+ } >+ >+ /* set the MTU for IP as well */ >+ memset(&ifr, 0, sizeof(ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ ifr.ifr_metric = link_mtu; >+ if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP MTU: %m"); >+ } >+} >+ >+/* >+ * ppp_set_xaccm - set the extended transmit ACCM for the interface. >+ */ >+void >+ppp_set_xaccm(unit, accm) >+ int unit; >+ ext_accm accm; >+{ >+ if (fdmuxid >= 0 >+ && strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_WARNING, "Couldn't set extended ACCM: %m"); >+ } >+} >+ >+/* >+ * ppp_recv_config - configure the receive-side characteristics of >+ * the ppp interface. >+ */ >+void >+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) >+ int unit, mru; >+ u_int32_t asyncmap; >+ int pcomp, accomp; >+{ >+ int cf[2]; >+ >+ link_mru = mru; >+ if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) { >+ if (hungup && errno == ENXIO) >+ return; >+ syslog(LOG_ERR, "Couldn't set MRU: %m"); >+ } >+ if (fdmuxid >= 0) { >+ /* can't set these if we don't have a stream attached below /dev/ppp */ >+ if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set receive ACCM: %m"); >+ } >+ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0); >+ cf[1] = DECOMP_PROT | DECOMP_AC; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m"); >+ } >+ } >+} >+ >+/* >+ * ccp_test - ask kernel whether a given compression method >+ * is acceptable for use. >+ */ >+int >+ccp_test(unit, opt_ptr, opt_len, for_transmit) >+ int unit, opt_len, for_transmit; >+ u_char *opt_ptr; >+{ >+ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP), >+ opt_ptr, opt_len, 0) >= 0) >+ return 1; >+ return (errno == ENOSR)? 0: -1; >+} >+ >+/* >+ * ccp_flags_set - inform kernel about the current state of CCP. >+ */ >+void >+ccp_flags_set(unit, isopen, isup) >+ int unit, isopen, isup; >+{ >+ int cf[2]; >+ >+ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0); >+ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (!hungup || errno != ENXIO) >+ syslog(LOG_ERR, "Couldn't set kernel CCP state: %m"); >+ } >+} >+ >+/* >+ * get_idle_time - return how long the link has been idle. >+ */ >+int >+get_idle_time(u, ip) >+ int u; >+ struct ppp_idle *ip; >+{ >+ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0; >+} >+ >+#if 0 >+/* >+ * set_filters - transfer the pass and active filters to the kernel. >+ */ >+int >+set_filters(pass, active) >+ struct bpf_program *pass, *active; >+{ >+ int ret = 1; >+ >+ if (pass->bf_len > 0) { >+ if (strioctl(pppfd, PPPIO_PASSFILT, pass, >+ sizeof(struct bpf_program), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m"); >+ ret = 0; >+ } >+ } >+ if (active->bf_len > 0) { >+ if (strioctl(pppfd, PPPIO_ACTIVEFILT, active, >+ sizeof(struct bpf_program), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m"); >+ ret = 0; >+ } >+ } >+ return ret; >+} >+#endif >+ >+/* >+ * ccp_fatal_error - returns 1 if decompression was disabled as a >+ * result of an error detected after decompression of a packet, >+ * 0 otherwise. This is necessary because of patent nonsense. >+ */ >+int >+ccp_fatal_error(unit) >+ int unit; >+{ >+ int cf[2]; >+ >+ cf[0] = cf[1] = 0; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (errno != ENXIO && errno != EINVAL) >+ syslog(LOG_ERR, "Couldn't get compression flags: %m"); >+ return 0; >+ } >+ return cf[0] & CCP_FATALERROR; >+} >+ >+/* >+ * sifvjcomp - config tcp header compression >+ */ >+int >+sifvjcomp(u, vjcomp, xcidcomp, xmaxcid) >+ int u, vjcomp, xcidcomp, xmaxcid; >+{ >+ int cf[2]; >+ char maxcid[2]; >+ >+ if (vjcomp) { >+ maxcid[0] = xcidcomp; >+ maxcid[1] = 15; /* XXX should be rmaxcid */ >+ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) { >+ syslog(LOG_ERR, "Couldn't initialize VJ compression: %m"); >+ } >+ } >+ >+ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */ >+ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0); >+ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID; >+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { >+ if (vjcomp) >+ syslog(LOG_ERR, "Couldn't enable VJ compression: %m"); >+ } >+ >+ return 1; >+} >+ >+/* >+ * sifup - Config the interface up and enable IP packets to pass. >+ */ >+int >+sifup(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (get): %m"); >+ return 0; >+ } >+ ifr.ifr_flags |= IFF_UP; >+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface up (set): %m"); >+ return 0; >+ } >+ if_is_up = 1; >+ return 1; >+} >+ >+/* >+ * sifdown - Config the interface down and disable IP. >+ */ >+int >+sifdown(u) >+ int u; >+{ >+ struct ifreq ifr; >+ >+ if (ipmuxid < 0) >+ return 1; >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (get): %m"); >+ return 0; >+ } >+ ifr.ifr_flags &= ~IFF_UP; >+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface down (set): %m"); >+ return 0; >+ } >+ if_is_up = 0; >+ return 1; >+} >+ >+/* >+ * sifnpmode - Set the mode for handling packets for a given NP. >+ */ >+int >+sifnpmode(u, proto, mode) >+ int u; >+ int proto; >+ enum NPmode mode; >+{ >+ int npi[2]; >+ >+ npi[0] = proto; >+ npi[1] = (int) mode; >+ if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) { >+ syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode); >+ return 0; >+ } >+ return 1; >+} >+ >+#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr) >+ >+/* >+ * sifaddr - Config the interface IP addresses and netmask. >+ */ >+int >+sifaddr(u, o, h, m) >+ int u; >+ u_int32_t o, h, m; >+{ >+ struct ifreq ifr; >+ int ret = 1; >+ >+ memset(&ifr, 0, sizeof(ifr)); >+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); >+ ifr.ifr_addr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_addr) = m; >+ if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP netmask: %m"); >+ ret = 0; >+ } >+ ifr.ifr_addr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_addr) = o; >+ if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set local IP address: %m"); >+ ret = 0; >+ } >+ >+ /* >+ * On some systems, we have to explicitly set the point-to-point >+ * flag bit before we can set a destination address. >+ */ >+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) >= 0 >+ && (ifr.ifr_flags & IFF_POINTOPOINT) == 0) { >+ ifr.ifr_flags |= IFF_POINTOPOINT; >+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't mark interface pt-to-pt: %m"); >+ ret = 0; >+ } >+ } >+ ifr.ifr_dstaddr.sa_family = AF_INET; >+ INET_ADDR(ifr.ifr_dstaddr) = h; >+ if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set remote IP address: %m"); >+ ret = 0; >+ } >+#if 0 /* now done in ppp_send_config */ >+ ifr.ifr_metric = link_mtu; >+ if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) { >+ syslog(LOG_ERR, "Couldn't set IP MTU: %m"); >+ } >+#endif >+ >+ return ret; >+} >+ >+/* >+ * cifaddr - Clear the interface IP addresses, and delete routes >+ * through the interface if possible. >+ */ >+int >+cifaddr(u, o, h) >+ int u; >+ u_int32_t o, h; >+{ >+#if defined(__USLC__) /* was: #if 0 */ >+ cifroute(unit, ouraddr, hisaddr); >+ if (ipmuxid >= 0) { >+ syslog(LOG_NOTICE, "Removing ppp interface unit"); >+ if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) { >+ syslog(LOG_ERR, "Can't remove ppp interface unit: %m"); >+ return 0; >+ } >+ ipmuxid = -1; >+ } >+#endif >+ return 1; >+} >+ >+/* >+ * sifdefaultroute - assign a default route through the address given. >+ */ >+int >+sifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct rtentry rt; >+ >+#if defined(__USLC__) >+ g = l; /* use the local address as gateway */ >+#endif >+ memset(&rt, 0, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = 0; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = g; >+ rt.rt_flags = RTF_GATEWAY; >+ >+ if (ioctl(ipfd, SIOCADDRT, &rt) < 0) { >+ syslog(LOG_ERR, "Can't add default route: %m"); >+ return 0; >+ } >+ >+ default_route_gateway = g; >+ return 1; >+} >+ >+/* >+ * cifdefaultroute - delete a default route through the address given. >+ */ >+int >+cifdefaultroute(u, l, g) >+ int u; >+ u_int32_t l, g; >+{ >+ struct rtentry rt; >+ >+#if defined(__USLC__) >+ g = l; /* use the local address as gateway */ >+#endif >+ memset(&rt, 0, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = 0; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = g; >+ rt.rt_flags = RTF_GATEWAY; >+ >+ if (ioctl(ipfd, SIOCDELRT, &rt) < 0) { >+ syslog(LOG_ERR, "Can't delete default route: %m"); >+ return 0; >+ } >+ >+ default_route_gateway = 0; >+ return 1; >+} >+ >+/* >+ * sifproxyarp - Make a proxy ARP entry for the peer. >+ */ >+int >+sifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ memset(&arpreq, 0, sizeof(arpreq)); >+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) >+ return 0; >+ >+ arpreq.arp_pa.sa_family = AF_INET; >+ INET_ADDR(arpreq.arp_pa) = hisaddr; >+ arpreq.arp_flags = ATF_PERM | ATF_PUBL; >+ if (ioctl(ipfd, SIOCSARP, (caddr_t) &arpreq) < 0) { >+ syslog(LOG_ERR, "Couldn't set proxy ARP entry: %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = hisaddr; >+ return 1; >+} >+ >+/* >+ * cifproxyarp - Delete the proxy ARP entry for the peer. >+ */ >+int >+cifproxyarp(unit, hisaddr) >+ int unit; >+ u_int32_t hisaddr; >+{ >+ struct arpreq arpreq; >+ >+ memset(&arpreq, 0, sizeof(arpreq)); >+ arpreq.arp_pa.sa_family = AF_INET; >+ INET_ADDR(arpreq.arp_pa) = hisaddr; >+ if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) { >+ syslog(LOG_ERR, "Couldn't delete proxy ARP entry: %m"); >+ return 0; >+ } >+ >+ proxy_arp_addr = 0; >+ return 1; >+} >+ >+/* >+ * get_ether_addr - get the hardware address of an interface on the >+ * the same subnet as ipaddr. >+ */ >+#define MAX_IFS 32 >+ >+static int >+get_ether_addr(ipaddr, hwaddr) >+ u_int32_t ipaddr; >+ struct sockaddr *hwaddr; >+{ >+ struct ifreq *ifr, *ifend, ifreq; >+ int nif; >+ struct ifconf ifc; >+ u_int32_t ina, mask; >+ >+ /* >+ * Scan through the system's network interfaces. >+ */ >+#ifdef SIOCGIFNUM >+ if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0) >+#endif >+ nif = MAX_IFS; >+ ifc.ifc_len = nif * sizeof(struct ifreq); >+ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len); >+ if (ifc.ifc_buf == 0) >+ return 0; >+ if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_WARNING, "Couldn't get system interface list: %m"); >+ free(ifc.ifc_buf); >+ return 0; >+ } >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) { >+ if (ifr->ifr_addr.sa_family != AF_INET) >+ continue; >+ /* >+ * Check that the interface is up, and not point-to-point or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & >+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) >+ != (IFF_UP|IFF_BROADCAST)) >+ continue; >+ /* >+ * Get its netmask and check that it's on the right subnet. >+ */ >+ if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ ina = INET_ADDR(ifr->ifr_addr); >+ mask = INET_ADDR(ifreq.ifr_addr); >+ if ((ipaddr & mask) == (ina & mask)) >+ break; >+ } >+ >+ if (ifr >= ifend) { >+ syslog(LOG_WARNING, "No suitable interface found for proxy ARP"); >+ free(ifc.ifc_buf); >+ return 0; >+ } >+ >+ syslog(LOG_INFO, "found interface %s for proxy ARP", ifr->ifr_name); >+ if (!get_hw_addr(ifr->ifr_name, hwaddr)) { >+ syslog(LOG_ERR, "Couldn't get hardware address for %s", ifr->ifr_name); >+ free(ifc.ifc_buf); >+ return 0; >+ } >+ >+ free(ifc.ifc_buf); >+ return 1; >+} >+ >+/* >+ * get_hw_addr - obtain the hardware address for a named interface. >+ */ >+static int >+get_hw_addr(name, hwaddr) >+ char *name; >+ struct sockaddr *hwaddr; >+{ >+ char *p, *q; >+ int unit, iffd, adrlen; >+ unsigned char *adrp; >+ char ifdev[24]; >+ struct { >+ union DL_primitives prim; >+ char space[64]; >+ } reply; >+ >+ /* >+ * We have to open the device and ask it for its hardware address. >+ * First split apart the device name and unit. >+ */ >+ strcpy(ifdev, "/dev/"); >+ q = ifdev + 5; /* strlen("/dev/") */ >+ while (*name != 0 && !isdigit(*name)) >+ *q++ = *name++; >+ *q = 0; >+ unit = atoi(name); >+ >+ /* >+ * Open the device and do a DLPI attach and phys_addr_req. >+ */ >+ iffd = open(ifdev, O_RDWR); >+ if (iffd < 0) { >+ syslog(LOG_ERR, "Can't open %s: %m", ifdev); >+ return 0; >+ } >+ if (dlpi_attach(iffd, unit) < 0 >+ || dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0 >+ || dlpi_info_req(iffd) < 0 >+ || dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) { >+ close(iffd); >+ return 0; >+ } >+ >+ adrlen = reply.prim.info_ack.dl_addr_length; >+ adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset; >+#if DL_CURRENT_VERSION >= 2 >+ if (reply.prim.info_ack.dl_sap_length < 0) >+ adrlen += reply.prim.info_ack.dl_sap_length; >+ else >+ adrp += reply.prim.info_ack.dl_sap_length; >+#endif >+ hwaddr->sa_family = AF_UNSPEC; >+ memcpy(hwaddr->sa_data, adrp, adrlen); >+ >+ return 1; >+} >+ >+static int >+dlpi_attach(fd, ppa) >+ int fd, ppa; >+{ >+ dl_attach_req_t req; >+ struct strbuf buf; >+ >+ req.dl_primitive = DL_ATTACH_REQ; >+ req.dl_ppa = ppa; >+ buf.len = sizeof(req); >+ buf.buf = (void *) &req; >+ return putmsg(fd, &buf, NULL, RS_HIPRI); >+} >+ >+static int >+dlpi_info_req(fd) >+ int fd; >+{ >+ dl_info_req_t req; >+ struct strbuf buf; >+ >+ req.dl_primitive = DL_INFO_REQ; >+ buf.len = sizeof(req); >+ buf.buf = (void *) &req; >+ return putmsg(fd, &buf, NULL, RS_HIPRI); >+} >+ >+static int >+dlpi_get_reply(fd, reply, expected_prim, maxlen) >+ union DL_primitives *reply; >+ int fd, expected_prim, maxlen; >+{ >+ struct strbuf buf; >+ int flags, n; >+ struct pollfd pfd; >+ >+ /* >+ * Use poll to wait for a message with a timeout. >+ */ >+ pfd.fd = fd; >+ pfd.events = POLLIN | POLLPRI; >+ do { >+ n = poll(&pfd, 1, 1000); >+ } while (n == -1 && errno == EINTR); >+ if (n <= 0) >+ return -1; >+ >+ /* >+ * Get the reply. >+ */ >+ buf.maxlen = maxlen; >+ buf.buf = (void *) reply; >+ flags = 0; >+ if (getmsg(fd, &buf, NULL, &flags) < 0) >+ return -1; >+ >+ if (buf.len < sizeof(ulong)) { >+ if (debug) >+ syslog(LOG_DEBUG, "dlpi response short (len=%d)\n", buf.len); >+ return -1; >+ } >+ >+ if (reply->dl_primitive == expected_prim) >+ return 0; >+ >+ if (debug) { >+ if (reply->dl_primitive == DL_ERROR_ACK) { >+ syslog(LOG_DEBUG, "dlpi error %d (unix errno %d) for prim %x\n", >+ reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno, >+ reply->error_ack.dl_error_primitive); >+ } else { >+ syslog(LOG_DEBUG, "dlpi unexpected response prim %x\n", >+ reply->dl_primitive); >+ } >+ } >+ >+ return -1; >+} >+ >+/* >+ * Return user specified netmask, modified by any mask we might determine >+ * for address `addr' (in network byte order). >+ * Here we scan through the system's list of interfaces, looking for >+ * any non-point-to-point interfaces which might appear to be on the same >+ * network as `addr'. If we find any, we OR in their netmask to the >+ * user-specified netmask. >+ */ >+u_int32_t >+GetMask(addr) >+ u_int32_t addr; >+{ >+ u_int32_t mask, nmask, ina; >+ struct ifreq *ifr, *ifend, ifreq; >+ int nif; >+ struct ifconf ifc; >+ >+ addr = ntohl(addr); >+ if (IN_CLASSA(addr)) /* determine network mask for address class */ >+ nmask = IN_CLASSA_NET; >+ else if (IN_CLASSB(addr)) >+ nmask = IN_CLASSB_NET; >+ else >+ nmask = IN_CLASSC_NET; >+ /* class D nets are disallowed by bad_ip_adrs */ >+ mask = netmask | htonl(nmask); >+ >+ /* >+ * Scan through the system's network interfaces. >+ */ >+#ifdef SIOCGIFNUM >+ if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0) >+#endif >+ nif = MAX_IFS; >+ ifc.ifc_len = nif * sizeof(struct ifreq); >+ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len); >+ if (ifc.ifc_buf == 0) >+ return mask; >+ if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) { >+ syslog(LOG_WARNING, "Couldn't get system interface list: %m"); >+ free(ifc.ifc_buf); >+ return mask; >+ } >+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); >+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) { >+ /* >+ * Check the interface's internet address. >+ */ >+ if (ifr->ifr_addr.sa_family != AF_INET) >+ continue; >+ ina = INET_ADDR(ifr->ifr_addr); >+ if ((ntohl(ina) & nmask) != (addr & nmask)) >+ continue; >+ /* >+ * Check that the interface is up, and not point-to-point or loopback. >+ */ >+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); >+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0) >+ continue; >+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) >+ != IFF_UP) >+ continue; >+ /* >+ * Get its netmask and OR it into our mask. >+ */ >+ if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0) >+ continue; >+ mask |= INET_ADDR(ifreq.ifr_addr); >+ } >+ >+ free(ifc.ifc_buf); >+ return mask; >+} >+ >+/* >+ * logwtmp - write an accounting record to the /var/adm/wtmp file. >+ */ >+void >+logwtmp(line, name, host) >+ const char *line, *name, *host; >+{ >+ static struct utmpx utmpx; >+ >+ if (name[0] != 0) { >+ /* logging in */ >+ strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user)); >+ strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id)); >+ strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line)); >+ utmpx.ut_pid = getpid(); >+ utmpx.ut_type = USER_PROCESS; >+ } else { >+ utmpx.ut_type = DEAD_PROCESS; >+ } >+ gettimeofday(&utmpx.ut_tv, NULL); >+ updwtmpx("/var/adm/wtmpx", &utmpx); >+} >+ >+/* >+ * get_host_seed - return the serial number of this machine. >+ */ >+int >+get_host_seed() >+{ >+ char buf[32]; >+ >+ if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) < 0) { >+ syslog(LOG_ERR, "sysinfo: %m"); >+ return 0; >+ } >+ return (int) strtoul(buf, NULL, 16); >+} >+ >+static int >+strioctl(fd, cmd, ptr, ilen, olen) >+ int fd, cmd, ilen, olen; >+ void *ptr; >+{ >+ struct strioctl str; >+ >+ str.ic_cmd = cmd; >+ str.ic_timout = 0; >+ str.ic_len = ilen; >+ str.ic_dp = ptr; >+ if (ioctl(fd, I_STR, &str) == -1) >+ return -1; >+ if (str.ic_len != olen) >+ syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n", >+ olen, str.ic_len, cmd); >+ return 0; >+} >+ >+/* >+ * lock - create a lock file for the named lock device >+ */ >+ >+#define LOCK_PREFIX "/var/spool/locks/LK." >+static char lock_file[40]; /* name of lock file created */ >+ >+int >+lock(dev) >+ char *dev; >+{ >+ int n, fd, pid; >+ struct stat sbuf; >+ char ascii_pid[12]; >+ >+ if (stat(dev, &sbuf) < 0) { >+ syslog(LOG_ERR, "Can't get device number for %s: %m", dev); >+ return -1; >+ } >+ if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { >+ syslog(LOG_ERR, "Can't lock %s: not a character device", dev); >+ return -1; >+ } >+ sprintf(lock_file, "%s%03d.%03d.%03d", LOCK_PREFIX, major(sbuf.st_dev), >+ major(sbuf.st_rdev), minor(sbuf.st_rdev)); >+ >+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { >+ if (errno == EEXIST >+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { >+ /* Read the lock file to find out who has the device locked */ >+ n = read(fd, ascii_pid, 11); >+ if (n <= 0) { >+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); >+ close(fd); >+ } else { >+ ascii_pid[n] = 0; >+ pid = atoi(ascii_pid); >+ if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) { >+ /* pid no longer exists - remove the lock file */ >+ if (unlink(lock_file) == 0) { >+ close(fd); >+ syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", >+ dev, pid); >+ continue; >+ } else >+ syslog(LOG_WARNING, "Couldn't remove stale lock on %s", >+ dev); >+ } else >+ syslog(LOG_NOTICE, "Device %s is locked by pid %d", >+ dev, pid); >+ } >+ close(fd); >+ } else >+ syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); >+ lock_file[0] = 0; >+ return -1; >+ } >+ >+ sprintf(ascii_pid, "%10d\n", getpid()); >+ write(fd, ascii_pid, 11); >+ >+ close(fd); >+ return 1; >+} >+ >+/* >+ * unlock - remove our lockfile >+ */ >+void >+unlock() >+{ >+ if (lock_file[0]) { >+ unlink(lock_file); >+ lock_file[0] = 0; >+ } >+} >+ >+ >+/* >+ * cifroute - delete a route through the addresses given. >+ */ >+int >+cifroute(u, our, his) >+ int u; >+ u_int32_t our, his; >+{ >+ struct rtentry rt; >+ >+ memset(&rt, 0, sizeof(rt)); >+ rt.rt_dst.sa_family = AF_INET; >+ INET_ADDR(rt.rt_dst) = his; >+ rt.rt_gateway.sa_family = AF_INET; >+ INET_ADDR(rt.rt_gateway) = our; >+ rt.rt_flags = RTF_HOST; >+ >+ if (ioctl(ipfd, SIOCDELRT, &rt) < 0) { >+ syslog(LOG_ERR, "Can't delete route: %m"); >+ return 0; >+ } >+ >+ return 1; >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 15619
: 7093