This patch is against ppp 2.3.7 (Debian source tree) and is released under the GNU General Public License. If you use it, you're on your own. David Luyer University Computing Services University of Western Australia diff -ur ORIG/ppp-2.3.7/pppd/auth.c ppp-2.3.7/pppd/auth.c --- ORIG/ppp-2.3.7/pppd/auth.c Thu Apr 1 15:07:44 1999 +++ ppp-2.3.7/pppd/auth.c Tue Jun 1 01:26:12 1999 @@ -60,6 +60,8 @@ #include #endif +#define ERPCD_EVILNESS 1 + #ifdef HAS_SHADOW #include #ifndef PW_PPP @@ -151,6 +153,9 @@ static void check_idle __P((void *)); static void connect_time_expired __P((void *)); static int plogin __P((char *, char *, char **, int *)); +#if ERPCD_EVILNESS +static int erpcdlogin __P((char *, char *)); +#endif static void plogout __P((void)); static int null_login __P((int)); static int get_pap_passwd __P((char *)); @@ -210,6 +215,11 @@ "Get PAP user and password from file" }, { "privgroup", o_special, privgroup, "Allow group members to use privileged options", OPT_PRIV }, +#if ERPCD_EVILNESS + { "erpcd", o_string, our_erpcd, + "ERPCD for PAP auth and IP allocation", OPT_STATIC, + NULL, MAXNAMELEN }, +#endif { NULL } }; @@ -680,7 +690,11 @@ * to authenticate the peer. */ lacks_ip = 0; +#if ERPCD_EVILNESS + can_auth = wo->neg_upap && (our_erpcd[0] != '\0' || uselogin || have_pap_secret(&lacks_ip)); +#else can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); +#endif if (!can_auth && wo->neg_chap) { can_auth = have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, &lacks_ip); @@ -723,7 +737,11 @@ && have_chap_secret(user, (explicit_remote? remote_name: NULL), 0, NULL); +#if ERPCD_EVILNESS + if (go->neg_upap && our_erpcd[0] == '\0' && !uselogin && !have_pap_secret(NULL)) +#else if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) +#endif go->neg_upap = 0; if (go->neg_chap) { if (!have_chap_secret((explicit_remote? remote_name: NULL), @@ -800,6 +818,15 @@ } } +#if ERPCD_EVILNESS + if (our_erpcd[0] != '\0' && ret == UPAP_AUTHACK) { + ret = erpcdlogin(user, passwd); + if (ret == UPAP_AUTHNAK) { + warn("PAP ERPCD login failure for %s", user); + } + } +#endif + if (ret == UPAP_AUTHNAK) { if (*msg == (char *) 0) *msg = "Login incorrect"; @@ -1029,6 +1056,185 @@ return (UPAP_AUTHACK); } +#if ERPCD_EVILNESS +/* + * erpcdsetip - find an IP address for the user from an erpcd. + * if none is returned, deny login. + * returns: UPAP_AUTHACK or UPAP_AUTHNAK. + */ +static int +erpcdsetip(user) + char *user; +{ + int sd; +#if 0 + int id, seq; +#endif + struct sockaddr_in Server; + char buf1[64] = { 0x01, 0x02, 0x03, 0x04, + 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, + 0x00, 0x0f, /* srpc init */ + 0x00, 0x00, 0x00, 0x00, /* srpc_id */ + 0x00, 0x00, 0x00, 0x00, /* sequence # */ + 0x00 }; /* truncated key to be ignored */ + char buf2[187] = { 0x01, 0x02, 0x03, 0x04, + 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, + 0x00, 0x15, /* req dialup addr */ + 0x00, 0x00, 0x00, 0x00, /* srpc_id */ + 0x00, 0x00, 0x00, 0x00, /* sequence # */ + 0x00, 0x00, 0x00, 0x00, /* handle */ + 0x00, 0x00, 0x00, 0x00, /* logid */ + 0x00, 0x00, 0x00, 0x00, /* inet */ + 0x00, 0x00, /* port */ + 0x00, 0x06, /* service */ + 0x00, 0x00, 0x00, 0x00, /* loc */ + 0x00, 0x00, 0x00, 0x00, /* rem */ + /* + 129 user */ + /* + 6 node */ + /* + 2 alignment (dummy) */ }; + + /* BUG: udp packets aren't always accepted by the same process + * so sometimes they id is 0. so use 0. */ +#if 0 + srandom(getpid() ^ time(NULL)); + *(int *)(buf1+18) = id = random(); + *(int *)(buf1+22) = seq = random(); + seq = htonl((htonl(seq) + 1)); + *(int *)(buf2+18) = id; + *(int *)(buf2+22) = seq; +#endif + memset(&Server, 0, sizeof(Server)); + Server.sin_family = AF_INET; + Server.sin_port = htons(121); + if ((Server.sin_addr.s_addr = inet_addr(our_erpcd)) == -1) { + struct hostent *host; + if ((host = gethostbyname(our_erpcd)) == NULL) + return (UPAP_AUTHNAK); + memcpy(&Server.sin_addr.s_addr, host->h_addr_list[0], 4); + } + strncpy(buf2+50, user, 32); + if (!*(buf2+50)) + return (UPAP_AUTHNAK); + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (UPAP_AUTHNAK); + if (sendto(sd, buf1, 27, 0, &Server, sizeof(Server)) < 0) + return (UPAP_AUTHNAK); + if (recv(sd, buf1, sizeof(buf1), 0) < 0) + return (UPAP_AUTHNAK); + if(*(buf1+4+2+1) != 2) + return (UPAP_AUTHNAK); + if (sendto(sd, buf2, 187, 0, &Server, sizeof(Server)) < 0) + return (UPAP_AUTHNAK); + if (recv(sd, buf2, sizeof(buf2), 0) != 42) + return (UPAP_AUTHNAK); + if(*(buf2+4+2+1) != 2 || *(int *)(buf2+22) != htonl(0xbabe3333ul)) + return (UPAP_AUTHNAK); + if (recv(sd, buf2, sizeof(buf2), 0) != 50) + return (UPAP_AUTHNAK); + if(*(buf2+4+2+1) != 0 || (*(int *)(buf2+30) != htonl(0xface1111ul) && + *(int *)(buf2+30) != htonl(0xdeaf2222ul))) + return (UPAP_AUTHNAK); + if(*(int *)(buf2+30) != htonl(0xface1111ul)) + return (UPAP_AUTHNAK); + ipcp_wantoptions[0].hisaddr = *(u_int32_t *)(buf2+38); + close(sd); + return (UPAP_AUTHACK); +} + +/* + * erpcdlogin - check username against erpcd. + * if anything goes wrong, this just bails out. + * returns: UPAP_AUTHACK or UPAP_AUTHNAK + */ +static int +erpcdlogin(user, passwd) + char *user; + char *passwd; +{ + int sd; +#if 0 + int id, seq; +#endif + struct sockaddr_in Server; + char buf1[64] = { 0x01, 0x02, 0x03, 0x04, + 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, + 0x00, 0x0f, /* srpc init */ + 0x00, 0x00, 0x00, 0x00, /* srpc_id */ + 0x00, 0x00, 0x00, 0x00, /* sequence # */ + 0x00 }; /* truncated key to be ignored */ + char buf2[210] = { 0x01, 0x02, 0x03, 0x04, + 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, + 0x00, 0x13, /* ppp auth */ + 0x00, 0x00, 0x00, 0x00, /* srpc_id */ + 0x00, 0x00, 0x00, 0x00, /* sequence # */ + 0x00, 0x00, 0x00, 0x00, /* handle */ + 0x00, 0x00, 0x00, 0x00, /* logid */ + 0x00, 0x00, 0x00, 0x00, /* inet */ + 0x00, 0x00, /* port */ + 0x00, 0x08, /* service */ + 0x00, 0x00, 0x00, 0x00, /* direction */ + /* + 32 user */ + /* + 32 pw */ + /* + 100 chars filler */ }; + + /* BUG: udp packets aren't always accepted by the same process + * so sometimes they id is 0. so use 0. */ +#if 0 + srandom(getpid() ^ time(NULL)); + *(int *)(buf1+18) = id = random(); + *(int *)(buf1+22) = seq = random(); + seq = htonl((htonl(seq) + 1)); + *(int *)(buf2+18) = id; + *(int *)(buf2+22) = seq; +#endif + memset(&Server, 0, sizeof(Server)); + Server.sin_family = AF_INET; + Server.sin_port = htons(121); + if ((Server.sin_addr.s_addr = inet_addr(our_erpcd)) == -1) { + struct hostent *host; + if ((host = gethostbyname(our_erpcd)) == NULL) + return (UPAP_AUTHNAK); + memcpy(&Server.sin_addr.s_addr, host->h_addr_list[0], 4); + } + strncpy(buf2+46, user, 32); + strncpy(buf2+78, passwd, 32); + if (!*(buf2+46) || !*(buf2+78)) + return (UPAP_AUTHNAK); + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (UPAP_AUTHNAK); + if (sendto(sd, buf1, 27, 0, &Server, sizeof(Server)) < 0) + return (UPAP_AUTHNAK); + if (recv(sd, buf1, sizeof(buf1), 0) < 0) + return (UPAP_AUTHNAK); + if(*(buf1+4+2+1) != 2) + return (UPAP_AUTHNAK); + if (sendto(sd, buf2, 210, 0, &Server, sizeof(Server)) < 0) + return (UPAP_AUTHNAK); + if (recv(sd, buf2, sizeof(buf2), 0) != 26) + return (UPAP_AUTHNAK); + if(*(buf2+4+2+1) != 2 || *(int *)(buf2+22) != htonl(0xbabe3333ul)) + return (UPAP_AUTHNAK); + if (recv(sd, buf2, sizeof(buf2), 0) != 34) + return (UPAP_AUTHNAK); + if(*(buf2+4+2+1) != 0 || (*(int *)(buf2+30) != htonl(0xface1111ul) && + *(int *)(buf2+30) != htonl(0xdeaf2222ul))) + return (UPAP_AUTHNAK); + if(*(int *)(buf2+30) != htonl(0xface1111ul)) + return (UPAP_AUTHNAK); + close(sd); + /* now get IP address from erpcd */ + return erpcdsetip(user); +} +#endif /* ERPCD_EVILNESS */ + /* * plogout - Logout the user. */ diff -ur ORIG/ppp-2.3.7/pppd/options.c ppp-2.3.7/pppd/options.c --- ORIG/ppp-2.3.7/pppd/options.c Tue Mar 30 14:32:07 1999 +++ ppp-2.3.7/pppd/options.c Tue Jun 1 00:11:55 1999 @@ -82,6 +82,7 @@ char passwd[MAXSECRETLEN]; /* Password for PAP */ bool persist = 0; /* Reopen link after it goes down */ char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ +char our_erpcd[MAXNAMELEN]; /* ERPCD for PAP auth/IP allocation */ bool demand = 0; /* do dial-on-demand */ char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ int idle_time_limit = 0; /* Disconnect if idle for this many seconds */ diff -ur ORIG/ppp-2.3.7/pppd/pppd.h ppp-2.3.7/pppd/pppd.h --- ORIG/ppp-2.3.7/pppd/pppd.h Sat Jun 5 19:53:51 1999 +++ ppp-2.3.7/pppd/pppd.h Tue Jun 1 00:10:37 1999 @@ -173,6 +173,7 @@ extern bool uselogin; /* Use /etc/passwd for checking PAP */ extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */ extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +extern char our_erpcd[MAXNAMELEN]; /* ERPCD for PAP auth/IP allocation */ extern bool explicit_remote;/* remote_name specified with remotename opt */ extern bool demand; /* Do dial-on-demand */ extern char *ipparam; /* Extra parameter for ip up/down scripts */