]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/ppp/ppp.c
ppp: fix buffer overflow, set correct state after chap negotiation (thanks k0ga)
[plan9front.git] / sys / src / cmd / ip / ppp / ppp.c
1 /*
2  * ppp - point-to-point protocol, rfc1331
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <auth.h>
7 #include <bio.h>
8 #include <ip.h>
9 #include <libsec.h>
10 #include <ndb.h>
11 #include "ppp.h"
12
13 #define PATH 128
14
15 static  int     baud;
16 static  int     nocompress;
17 static  int     pppframing = 1;
18 static  int     noipcompress;
19 static  int     server;
20 static  int noauth;
21 static  int     nip;            /* number of ip interfaces */
22 static  int     dying;          /* flag to signal to all threads its time to go */
23 static  int     primary;        /* this is the primary IP interface */
24 static  char    *chatfile;
25
26 int     debug;
27 char*   LOG = "ppp";
28 char*   keyspec = "";
29
30 enum
31 {
32         Rmagic= 0x12345
33 };
34
35 /*
36  * Calculate FCS - rfc 1331
37  */
38 ushort fcstab[256] =
39 {
40       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
41       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
42       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
43       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
44       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
45       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
46       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
47       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
48       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
49       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
50       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
51       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
52       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
53       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
54       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
55       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
56       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
57       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
58       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
59       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
60       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
61       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
62       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
63       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
64       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
65       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
66       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
67       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
68       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
69       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
70       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
71       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
72 };
73
74 static char *snames[] =
75 {
76         "Sclosed",
77         "Sclosing",
78         "Sreqsent",
79         "Sackrcvd",
80         "Sacksent",
81         "Sopened",
82 };
83
84 static  void            authtimer(PPP*);
85 static  void            chapinit(PPP*);
86 static  void            config(PPP*, Pstate*, int);
87 static  uchar*          escapeuchar(PPP*, ulong, uchar*, ushort*);
88 static  void            getchap(PPP*, Block*);
89 static  Block*          getframe(PPP*, int*);
90 static  void            getlqm(PPP*, Block*);
91 static  int             getopts(PPP*, Pstate*, Block*);
92 static  void            getpap(PPP*, Block*);
93 static  void            init(PPP*);
94 static  void            invalidate(Ipaddr);
95 static  void            ipinproc(PPP*);
96 static  char*           ipopen(PPP*);
97 static  void            mediainproc(PPP*);
98 static  void            newstate(PPP*, Pstate*, int);
99 static  int             nipifcs(char*);
100 static  void            papinit(PPP*);
101 static  void            pinit(PPP*, Pstate*);
102 static  void            ppptimer(PPP*);
103 static  void            printopts(Pstate*, Block*, int);
104 static  void            ptimer(PPP*, Pstate*);
105 static  int             putframe(PPP*, int, Block*);
106 static  void            putlqm(PPP*);
107 static  void            putndb(PPP*, char*);
108 static  void            putpaprequest(PPP*);
109 static  void            rcv(PPP*, Pstate*, Block*);
110 static  void            rejopts(PPP*, Pstate*, Block*, int);
111 static  void            sendechoreq(PPP*, Pstate*);
112 static  void            sendtermreq(PPP*, Pstate*);
113 static  void            setphase(PPP*, int);
114 static  void            terminate(PPP*, int);
115 static  int             validv4(Ipaddr);
116 static  void            dmppkt(char *s, uchar *a, int na);
117 static  void            getauth(PPP*);
118
119 void
120 pppopen(PPP *ppp, int mediain, int mediaout, char *net,
121         Ipaddr ipaddr, Ipaddr remip,
122         int mtu, int framing)
123 {
124         ppp->ipfd = -1;
125         ppp->ipcfd = -1;
126         invalidate(ppp->remote);
127         invalidate(ppp->local);
128         invalidate(ppp->curremote);
129         invalidate(ppp->curlocal);
130         invalidate(ppp->dns[0]);
131         invalidate(ppp->dns[1]);
132         invalidate(ppp->wins[0]);
133         invalidate(ppp->wins[1]);
134
135         ppp->mediain = mediain;
136         ppp->mediaout = mediaout;
137         if(validv4(remip)){
138                 ipmove(ppp->remote, remip);
139                 ppp->remotefrozen = 1;
140         }
141         if(validv4(ipaddr)){
142                 ipmove(ppp->local, ipaddr);
143                 ppp->localfrozen = 1;
144         }
145         ppp->mtu = Defmtu;
146         ppp->mru = mtu;
147         ppp->framing = framing;
148         ppp->net = net;
149
150         init(ppp);
151         switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
152         case -1:
153                 sysfatal("forking mediainproc");
154         case 0:
155                 mediainproc(ppp);
156                 terminate(ppp, 1);
157                 _exits(0);
158         }
159 }
160
161 static void
162 init(PPP* ppp)
163 {
164         if(ppp->inbuf == nil){
165                 ppp->inbuf = allocb(4096);
166                 if(ppp->inbuf == nil)
167                         abort();
168
169                 ppp->outbuf = allocb(4096);
170                 if(ppp->outbuf == nil)
171                         abort();
172
173                 ppp->lcp = mallocz(sizeof(*ppp->lcp), 1);
174                 if(ppp->lcp == nil)
175                         abort();
176                 ppp->lcp->proto = Plcp;
177                 ppp->lcp->state = Sclosed;
178
179                 ppp->ccp = mallocz(sizeof(*ppp->ccp), 1);
180                 if(ppp->ccp == nil)
181                         abort();
182                 ppp->ccp->proto = Pccp;
183                 ppp->ccp->state = Sclosed;
184
185                 ppp->ipcp = mallocz(sizeof(*ppp->ipcp), 1);
186                 if(ppp->ipcp == nil)
187                         abort();
188                 ppp->ipcp->proto = Pipcp;
189                 ppp->ipcp->state = Sclosed;
190
191                 ppp->chap = mallocz(sizeof(*ppp->chap), 1);
192                 if(ppp->chap == nil)
193                         abort();
194                 ppp->chap->proto = APmschap;
195                 ppp->chap->state = Cunauth;
196                 auth_freechal(ppp->chap->cs);
197                 ppp->chap->cs = nil;
198
199                 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
200                 case -1:
201                         sysfatal("forking ppptimer");
202                 case 0:
203                         ppptimer(ppp);
204                         _exits(0);
205                 }
206         }
207
208         ppp->ctcp = compress_init(ppp->ctcp);
209         pinit(ppp, ppp->lcp);
210         setphase(ppp, Plink);
211 }
212
213 static void
214 setphase(PPP *ppp, int phase)
215 {
216         int oldphase;
217
218         oldphase = ppp->phase;
219
220         ppp->phase = phase;
221         switch(phase){
222         default:
223                 sysfatal("ppp: unknown phase %d", phase);
224         case Pdead:
225                 /* restart or exit? */
226                 pinit(ppp, ppp->lcp);
227                 setphase(ppp, Plink);
228                 break;
229         case Plink:
230                 /* link down */
231                 switch(oldphase) {
232                 case Pauth:
233                         auth_freechal(ppp->chap->cs);
234                         ppp->chap->cs = nil;
235                         ppp->chap->state = Cunauth;
236                         break;
237                 case Pnet:
238                         auth_freechal(ppp->chap->cs);
239                         ppp->chap->cs = nil;
240                         ppp->chap->state = Cunauth;
241                         newstate(ppp, ppp->ccp, Sclosed);
242                         newstate(ppp, ppp->ipcp, Sclosed);
243                 }
244                 break;
245         case Pauth:
246                 if(server) {
247                         chapinit(ppp);
248                 } else {
249                         switch (ppp->chap->proto) {
250                         case APpasswd:
251                                 papinit(ppp);
252                                 break;
253                         case APmd5:
254                         case APmschap:
255                                 break;
256                         default:
257                                 setphase(ppp, Pnet);
258                                 break;
259                         }
260                 }
261                 break;
262         case Pnet:
263                 pinit(ppp, ppp->ccp);
264                 pinit(ppp, ppp->ipcp);
265                 break;
266         case Pterm:
267                 /* what? */
268                 break;
269         }
270 }
271
272 static void
273 pinit(PPP *ppp, Pstate *p)
274 {
275         p->timeout = 0;
276
277         switch(p->proto){
278         case Plcp:
279                 ppp->magic = truerand();
280                 ppp->xctlmap = 0xffffffff;
281                 ppp->period = 0;
282                 p->optmask = 0xffffffff;
283                 if(!server)
284                         p->optmask &=  ~(Fauth|Fmtu);
285                 ppp->rctlmap = 0;
286                 ppp->ipcp->state = Sclosed;
287                 ppp->ipcp->optmask = 0xffffffff;
288                 if(noipcompress) {
289                         p->optmask &= ~Fac;
290                         ppp->ipcp->optmask &= ~Fipaddrs;
291                 }
292                 if(nocompress) {
293                         p->optmask &= ~Fpc;
294                         ppp->ipcp->optmask &= ~Fipcompress;
295                 }
296                 p->echotimeout = 0;
297
298                 /* quality goo */
299                 ppp->timeout = 0;
300                 memset(&ppp->in, 0, sizeof(ppp->in));
301                 memset(&ppp->out, 0, sizeof(ppp->out));
302                 memset(&ppp->pin, 0, sizeof(ppp->pin));
303                 memset(&ppp->pout, 0, sizeof(ppp->pout));
304                 memset(&ppp->sin, 0, sizeof(ppp->sin));
305                 break;
306         case Pccp:
307                 if(nocompress)
308                         p->optmask = 0;
309                 else
310                         p->optmask = Fcmppc;
311
312                 if(ppp->ctype != nil)
313                         (*ppp->ctype->fini)(ppp->cstate);
314                 ppp->ctype = nil;
315                 ppp->ctries = 0;
316                 ppp->cstate = nil;
317
318                 if(ppp->unctype)
319                         (*ppp->unctype->fini)(ppp->uncstate);
320                 ppp->unctype = nil;
321                 ppp->uncstate = nil;
322                 break;
323         case Pipcp:
324                 p->optmask = 0xffffffff;
325                 ppp->ctcp = compress_init(ppp->ctcp);
326                 break;
327         }
328         p->confid = p->rcvdconfid = -1;
329         config(ppp, p, 1);
330         newstate(ppp, p, Sreqsent);
331 }
332
333 /*
334  *  change protocol to a new state.
335  */
336 static void
337 newstate(PPP *ppp, Pstate *p, int state)
338 {
339         char *err;
340
341         netlog("ppp: %ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld\n",
342                 p->proto, snames[p->state], snames[state], ppp->rctlmap,
343                 ppp->xctlmap, p->flags,
344                 ppp->mtu, ppp->mru);
345         syslog(0, "ppp", "%ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld",
346                 p->proto, snames[p->state], snames[state], ppp->rctlmap,
347                 ppp->xctlmap, p->flags,
348                 ppp->mtu, ppp->mru);
349
350         if(p->proto == Plcp) {
351                 if(state == Sopened)
352                         setphase(ppp, noauth? Pnet : Pauth);
353                 else if(state == Sclosed)
354                         setphase(ppp, Pdead);
355                 else if(p->state == Sopened)
356                         setphase(ppp, Plink);
357         }
358
359         if(p->proto == Pccp && state == Sopened) {
360                 if(ppp->unctype)
361                         (*ppp->unctype->fini)(ppp->uncstate);
362                 ppp->unctype = nil;
363                 ppp->uncstate = nil;
364                 if(p->optmask & Fcmppc) {
365                         ppp->unctype = &uncmppc;
366                         ppp->uncstate = (*uncmppc.init)(ppp);
367                 }
368                 if(p->optmask & Fcthwack){
369                         ppp->unctype = &uncthwack;
370                         ppp->uncstate = (*uncthwack.init)(ppp);
371                 }
372         }
373
374         if(p->proto == Pipcp && state == Sopened) {
375                 if(server && !noauth && ppp->chap->state != Cauthok)
376                         abort();
377
378                 err = ipopen(ppp);
379                 if(err != nil)
380                         sysfatal("%s", err);
381         }
382
383         p->state = state;
384 }
385
386 /* returns (protocol, information) */
387 static Block*
388 getframe(PPP *ppp, int *protop)
389 {
390         uchar *p, *from, *to;
391         int n, len, proto;
392         ulong c;
393         ushort fcs;
394         Block *buf, *b;
395
396         *protop = 0;
397         if(ppp->framing == 0) {
398                 /* assume data is already framed */
399                 b = allocb(2000);
400                 len = b->lim - b->wptr;
401                 n = read(ppp->mediain, b->wptr, len);
402                 dmppkt("RX", b->wptr, n);
403                 if(n <= 0 || n == len){
404                         freeb(b);
405
406                         return nil;
407                 }
408                 b->wptr += n;
409
410                 /* should probably copy to another block if small */
411
412                 if(pppframing && b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
413                         b->rptr += 2;
414                 proto = *b->rptr++;
415                 if((proto & 0x1) == 0)
416                         proto = (proto<<8) | *b->rptr++;
417
418                 if(b->rptr >= b->wptr){
419                         freeb(b);
420                         return nil;
421                 }
422
423                 ppp->in.uchars += n;
424                 ppp->in.packets++;
425                 *protop = proto;
426                 netlog("getframe 0x%x\n", proto);
427                 return b;
428         }
429
430         buf = ppp->inbuf;
431         for(;;){
432                 /* read till we hit a frame uchar or run out of room */
433                 for(p = buf->rptr; buf->wptr < buf->lim;){
434                         for(; p < buf->wptr; p++)
435                                 if(*p == HDLC_frame)
436                                         break;
437                         if(p != buf->wptr)
438                                 break;
439
440                         len = buf->lim - buf->wptr;
441                         n = read(ppp->mediain, buf->wptr, len);
442                         if(n <= 0){
443                                 syslog(0, LOG, "medium read returns %d: %r", n);
444                                 buf->wptr = buf->rptr;
445                                 return nil;
446                         }
447                         dmppkt("RX", buf->wptr, n);
448                         buf->wptr += n;
449                 }
450
451                 /* copy into block, undoing escapes, and caculating fcs */
452                 fcs = PPP_initfcs;
453                 b = allocb(p - buf->rptr);
454                 to = b->wptr;
455                 for(from = buf->rptr; from != p;){
456                         c = *from++;
457                         if(c == HDLC_esc){
458                                 if(from == p)
459                                         break;
460                                 c = *from++ ^ 0x20;
461                         } else if((c < 0x20) && (ppp->rctlmap & (1 << c)))
462                                 continue;
463                         *to++ = c;
464                         fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
465                 }
466
467                 /* copy down what's left in buffer */
468                 p++;
469                 memmove(buf->rptr, p, buf->wptr - p);
470                 n = p - buf->rptr;
471                 buf->wptr -= n;
472                 b->wptr = to - 2;
473
474                 /* return to caller if checksum matches */
475                 if(fcs == PPP_goodfcs){
476                         if(b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
477                                 b->rptr += 2;
478                         proto = *b->rptr++;
479                         if((proto & 0x1) == 0)
480                                 proto = (proto<<8) | *b->rptr++;
481                         if(b->rptr < b->wptr){
482                                 ppp->in.uchars += n;
483                                 ppp->in.packets++;
484                                 *protop = proto;
485                                 netlog("getframe 0x%x\n", proto);
486                                 return b;
487                         }
488                 } else if(BLEN(b) > 0){
489                         if(ppp->ctcp)
490                                 compress_error(ppp->ctcp);
491                         ppp->in.discards++;
492                         netlog("ppp: discard len %zd/%zd cksum %ux (%ux %ux %ux %ux)\n",
493                                 BLEN(b), BLEN(buf), fcs, b->rptr[0],
494                                 b->rptr[1], b->rptr[2], b->rptr[3]);
495                 }
496
497                 freeb(b);
498         }
499 }
500
501 /* send a PPP frame */
502 static int
503 putframe(PPP *ppp, int proto, Block *b)
504 {
505         Block *buf;
506         uchar *to, *from;
507         ushort fcs;
508         ulong ctlmap;
509         uchar c;
510         Block *bp;
511
512         ppp->out.packets++;
513
514         if(proto == Plcp)
515                 ctlmap = 0xffffffff;
516         else
517                 ctlmap = ppp->xctlmap;
518
519         /* make sure we have head room */
520         if(b->rptr - b->base < 4){
521                 b = padb(b, 4);
522                 b->rptr += 4;
523         }
524
525         netlog("ppp: putframe 0x%ux %zd\n", proto, BLEN(b));
526
527         /* add in the protocol and address, we'd better have left room */
528         from = b->rptr;
529         *--from = proto;
530         if(!(ppp->lcp->flags&Fpc) || proto > 0x100 || proto == Plcp)
531                 *--from = proto>>8;
532         if(pppframing && (!(ppp->lcp->flags&Fac) || proto == Plcp)){
533                 *--from = PPP_ctl;
534                 *--from = PPP_addr;
535         }
536
537         qlock(&ppp->outlock);
538         buf = ppp->outbuf;
539
540         if(ppp->framing == 0) {
541                 to = buf->rptr;
542                 for(bp = b; bp; bp = bp->next){
543                         if(bp != b)
544                                 from = bp->rptr;
545                         memmove(to, from, bp->wptr-from);
546                         to += bp->wptr-from;
547                 }
548         } else {
549                 /* escape and checksum the body */
550                 fcs = PPP_initfcs;
551                 to = buf->rptr;
552         
553                 /* add frame marker */
554                 *to++ = HDLC_frame;
555
556                 for(bp = b; bp; bp = bp->next){
557                         if(bp != b)
558                                 from = bp->rptr;
559                         for(; from < bp->wptr; from++){
560                                 c = *from;
561                                 if(c == HDLC_frame || c == HDLC_esc
562                                    || (c < 0x20 && ((1<<c) & ctlmap))){
563                                         *to++ = HDLC_esc;
564                                         *to++ = c ^ 0x20;
565                                 } else 
566                                         *to++ = c;
567                                 fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
568                         }
569                 }
570
571                 /* add on and escape the checksum */
572                 fcs = ~fcs;
573                 c = fcs;
574                 if(c == HDLC_frame || c == HDLC_esc
575                    || (c < 0x20 && ((1<<c) & ctlmap))){
576                         *to++ = HDLC_esc;
577                         *to++ = c ^ 0x20;
578                 } else 
579                         *to++ = c;
580                 c = fcs>>8;
581                 if(c == HDLC_frame || c == HDLC_esc
582                    || (c < 0x20 && ((1<<c) & ctlmap))){
583                         *to++ = HDLC_esc;
584                         *to++ = c ^ 0x20;
585                 } else 
586                         *to++ = c;
587         
588                 /* add frame marker */
589                 *to++ = HDLC_frame;
590         }
591
592         /* send */
593         buf->wptr = to;
594         dmppkt("TX", buf->rptr, BLEN(buf));
595         if(write(ppp->mediaout, buf->rptr, BLEN(buf)) < 0){
596                 qunlock(&ppp->outlock);
597                 return -1;
598         }
599         ppp->out.uchars += BLEN(buf);
600
601         qunlock(&ppp->outlock);
602         return 0;
603 }
604
605 Block*
606 alloclcp(int code, int id, int len, Lcpmsg **mp)
607 {
608         Block *b;
609         Lcpmsg *m;
610
611         /*
612          *  leave room for header
613          */
614         b = allocb(len);
615
616         m = (Lcpmsg*)b->wptr;
617         m->code = code;
618         m->id = id;
619         b->wptr += 4;
620
621         *mp = m;
622         return b;
623 }
624
625
626 static void
627 putlo(Block *b, int type, ulong val)
628 {
629         *b->wptr++ = type;
630         *b->wptr++ = 6;
631         hnputl(b->wptr, val);
632         b->wptr += 4;
633 }
634
635 static void
636 putv4o(Block *b, int type, Ipaddr val)
637 {
638         *b->wptr++ = type;
639         *b->wptr++ = 6;
640         v6tov4(b->wptr, val);
641         b->wptr += 4;
642 }
643
644 static void
645 putso(Block *b, int type, ulong val)
646 {
647         *b->wptr++ = type;
648         *b->wptr++ = 4;
649         hnputs(b->wptr, val);
650         b->wptr += 2;
651 }
652
653 static void
654 puto(Block *b, int type)
655 {
656         *b->wptr++ = type;
657         *b->wptr++ = 2;
658 }
659
660 /*
661  *  send configuration request
662  */
663 static void
664 config(PPP *ppp, Pstate *p, int newid)
665 {
666         Block *b;
667         Lcpmsg *m;
668         int id;
669
670         if(newid){
671                 id = p->id++;
672                 p->confid = id;
673                 p->timeout = Timeout;
674         } else
675                 id = p->confid;
676         b = alloclcp(Lconfreq, id, 256, &m);
677         USED(m);
678
679         switch(p->proto){
680         case Plcp:
681                 if(p->optmask & Fctlmap)
682                         putlo(b, Octlmap, 0);   /* we don't want anything escaped */
683                 if(p->optmask & Fmagic)
684                         putlo(b, Omagic, ppp->magic);
685                 if(p->optmask & Fmtu)
686                         putso(b, Omtu, ppp->mru);
687                 if(p->optmask & Fauth) {
688                         *b->wptr++ = Oauth;
689                         *b->wptr++ = 5;
690                         hnputs(b->wptr, Pchap);
691                         b->wptr += 2;
692                         *b->wptr++ = ppp->chap->proto;
693                 }
694                 if(p->optmask & Fpc)
695                         puto(b, Opc);
696                 if(p->optmask & Fac)
697                         puto(b, Oac);
698                 break;
699         case Pccp:
700                 if(p->optmask & Fcthwack)
701                         puto(b, Octhwack);
702                 else if(p->optmask & Fcmppc) {
703                         *b->wptr++ = Ocmppc;
704                         *b->wptr++ = 6;
705                         *b->wptr++ = 0;
706                         *b->wptr++ = 0;
707                         *b->wptr++ = 0;
708                         *b->wptr++ = 0x41;
709                 }
710                 break;
711         case Pipcp:
712                 if(p->optmask & Fipaddr){
713                         syslog(0, "ppp", "requesting %I", ppp->local);
714                         putv4o(b, Oipaddr, ppp->local);
715                 }
716                 if(primary && (p->optmask & Fipdns))
717                         putv4o(b, Oipdns, ppp->dns[0]);
718                 if(primary && (p->optmask & Fipdns2))
719                         putv4o(b, Oipdns2, ppp->dns[1]);
720                 if(primary && (p->optmask & Fipwins))
721                         putv4o(b, Oipwins, ppp->wins[0]);
722                 if(primary && (p->optmask & Fipwins2))
723                         putv4o(b, Oipwins2, ppp->wins[1]);
724                 /*
725                  * don't ask for header compression while data compression is still pending.
726                  * perhaps we should restart ipcp negotiation if compression negotiation fails.
727                  */
728                 if(!noipcompress && !ppp->ccp->optmask && (p->optmask & Fipcompress)) {
729                         *b->wptr++ = Oipcompress;
730                         *b->wptr++ = 6;
731                         hnputs(b->wptr, Pvjctcp);
732                         b->wptr += 2;
733                         *b->wptr++ = MAX_STATES-1;
734                         *b->wptr++ = 1;
735                 }
736                 break;
737         }
738         hnputs(m->len, BLEN(b));
739         printopts(p, b, 1);
740         putframe(ppp, p->proto, b);
741         freeb(b);
742 }
743
744 static void
745 getipinfo(PPP *ppp)
746 {
747         char *av[3];
748         int ndns, nwins;
749         char ip[64];
750         Ndbtuple *t, *nt;
751
752         if(!validv4(ppp->local))
753                 return;
754
755         av[0] = "dns";
756         av[1] = "wins";
757         sprint(ip, "%I", ppp->local);
758         t = csipinfo(ppp->net, "ip", ip, av, 2);
759         ndns = nwins = 0;
760         for(nt = t; nt != nil; nt = nt->entry){
761                 if(strcmp(nt->attr, "dns") == 0){
762                         if(ndns < 2)
763                                 parseip(ppp->dns[ndns++], nt->val);
764                 } else if(strcmp(nt->attr, "wins") == 0){
765                         if(nwins < 2)
766                                 parseip(ppp->wins[nwins++], nt->val);
767                 }
768         }
769         if(t != nil)
770                 ndbfree(t);
771 }
772
773 /*
774  *  parse configuration request, sends an ack or reject packet
775  *
776  *      returns:        -1 if request was syntacticly incorrect
777  *                       0 if packet was accepted
778  *                       1 if packet was rejected
779  */
780 static int
781 getopts(PPP *ppp, Pstate *p, Block *b)
782 {
783         Lcpmsg *m, *repm;       
784         Lcpopt *o;
785         uchar *cp, *ap;
786         ulong rejecting, nacking, flags, proto, chapproto;
787         ulong mtu, ctlmap, period;
788         ulong x;
789         Block *repb;
790         Comptype *ctype;
791         Ipaddr ipaddr;
792
793         rejecting = 0;
794         nacking = 0;
795         flags = 0;
796
797         /* defaults */
798         invalidate(ipaddr);
799         mtu = ppp->mtu;
800         ctlmap = 0xffffffff;
801         period = 0;
802         ctype = nil;
803         chapproto = 0;
804
805         m = (Lcpmsg*)b->rptr;
806         repb = alloclcp(Lconfack, m->id, BLEN(b), &repm);
807
808         /* copy options into ack packet */
809         memmove(repm->data, m->data, b->wptr - m->data);
810         repb->wptr += b->wptr - m->data;
811
812         /* look for options we don't recognize or like */
813         for(cp = m->data; cp < b->wptr; cp += o->len){
814                 o = (Lcpopt*)cp;
815                 if(cp + o->len > b->wptr || o->len==0){
816                         freeb(repb);
817                         netlog("ppp: bad option length %ux\n", o->type);
818                         return -1;
819                 }
820
821                 switch(p->proto){
822                 case Plcp:
823                         switch(o->type){
824                         case Oac:
825                                 flags |= Fac;
826                                 continue;
827                         case Opc:
828                                 flags |= Fpc;
829                                 continue;
830                         case Omtu:
831                                 mtu = nhgets(o->data);
832                                 continue;
833                         case Omagic:
834                                 if(ppp->magic == nhgetl(o->data))
835                                         netlog("ppp: possible loop\n");
836                                 continue;
837                         case Octlmap:
838                                 ctlmap = nhgetl(o->data);
839                                 continue;
840                         case Oquality:
841                                 proto = nhgets(o->data);
842                                 if(proto != Plqm)
843                                         break;
844                                 x = nhgetl(o->data+2)*10;
845                                 period = (x+Period-1)/Period;
846                                 continue;
847                         case Oauth:
848                                 proto = nhgets(o->data);
849                                 if(proto == Ppasswd && !server){
850                                         chapproto = APpasswd;
851                                         continue;
852                                 }
853                                 if(proto != Pchap)
854                                         break;
855                                 if(o->data[2] != APmd5 && o->data[2] != APmschap)
856                                         break;
857                                 chapproto = o->data[2];
858                                 continue;
859                         }
860                         break;
861                 case Pccp:
862                         if(nocompress)
863                                 break;
864                         switch(o->type){
865                         case Octhwack:
866                                 break;
867                         /*
868                                 if(o->len == 2){
869                                         ctype = &cthwack;
870                                         continue;
871                                 }
872                                 if(!nacking){
873                                         nacking = 1;
874                                         repb->wptr = repm->data;
875                                         repm->code = Lconfnak;
876                                 }
877                                 puto(repb, Octhwack);
878                                 continue;
879                         */
880                         case Ocmppc:
881                                 x = nhgetl(o->data);
882
883                                 // hack for Mac
884                                 // if(x == 0)
885                                 //      continue;
886
887                                 /* stop ppp loops */
888                                 if((x&0x41) == 0 || ppp->ctries++ > 5) {
889                                         /*
890                                          * turn off requests as well - I don't think this
891                                          * is needed in the standard
892                                          */
893                                         p->optmask &= ~Fcmppc;
894                                         break;
895                                 }
896                                 if(rejecting)
897                                         continue;
898                                 if(x & 1) {
899                                         ctype = &cmppc;
900                                         ppp->sendencrypted = (o->data[3]&0x40) == 0x40;
901                                         continue;
902                                 }
903                                 if(!nacking){
904                                         nacking = 1;
905                                         repb->wptr = repm->data;
906                                         repm->code = Lconfnak;
907                                 }
908                                 *repb->wptr++ = Ocmppc;
909                                 *repb->wptr++ = 6;
910                                 *repb->wptr++ = 0;
911                                 *repb->wptr++ = 0;
912                                 *repb->wptr++ = 0;
913                                 *repb->wptr++ = 0x41;
914                                 continue;
915                         }
916                         break;
917                 case Pipcp:
918                         switch(o->type){
919                         case Oipaddr:   
920                                 v4tov6(ipaddr, o->data);
921                                 if(!validv4(ppp->remote))
922                                         continue;
923                                 if(!validv4(ipaddr) && !rejecting){
924                                         /* other side requesting an address */
925                                         if(!nacking){
926                                                 nacking = 1;
927                                                 repb->wptr = repm->data;
928                                                 repm->code = Lconfnak;
929                                         }
930                                         putv4o(repb, Oipaddr, ppp->remote);
931                                 }
932                                 continue;
933                         case Oipdns:
934                                 ap = ppp->dns[0];
935                                 goto ipinfo;
936                         case Oipdns2:   
937                                 ap = ppp->dns[1];
938                                 goto ipinfo;
939                         case Oipwins:   
940                                 ap = ppp->wins[0];
941                                 goto ipinfo;
942                         case Oipwins2:
943                                 ap = ppp->wins[1];
944                                 goto ipinfo;
945                         ipinfo:
946                                 if(!validv4(ap))
947                                         getipinfo(ppp);
948                                 if(!validv4(ap))
949                                         break;
950                                 v4tov6(ipaddr, o->data);
951                                 if(!validv4(ipaddr) && !rejecting){
952                                         /* other side requesting an address */
953                                         if(!nacking){
954                                                 nacking = 1;
955                                                 repb->wptr = repm->data;
956                                                 repm->code = Lconfnak;
957                                         }
958                                         putv4o(repb, o->type, ap);
959                                 }
960                                 continue;
961                         case Oipcompress:
962                                 /*
963                                  * don't compress tcp header if we've negotiated data compression.
964                                  * tcp header compression has very poor performance if there is an error.
965                                  */
966                                 proto = nhgets(o->data);
967                                 if(noipcompress || proto != Pvjctcp || ppp->ctype != nil)
968                                         break;
969                                 if(compress_negotiate(ppp->ctcp, o->data+2) < 0)
970                                         break;
971                                 flags |= Fipcompress;
972                                 continue;
973                         }
974                         break;
975                 }
976
977                 /* come here if option is not recognized */
978                 if(!rejecting){
979                         rejecting = 1;
980                         repb->wptr = repm->data;
981                         repm->code = Lconfrej;
982                 }
983                 netlog("ppp: bad %ux option %d\n", p->proto, o->type);
984                 memmove(repb->wptr, o, o->len);
985                 repb->wptr += o->len;
986         }
987
988         /* permanent changes only after we know that we liked the packet */
989         if(!rejecting && !nacking){
990                 switch(p->proto){
991                 case Plcp:
992                         ppp->period = period;
993                         ppp->xctlmap = ctlmap;
994                         if(mtu > Maxmtu)
995                                 mtu = Maxmtu;
996                         if(mtu < Minmtu)
997                                 mtu = Minmtu;
998                         ppp->mtu = mtu;
999                         if(chapproto)
1000                                 ppp->chap->proto = chapproto;
1001                         
1002                         break;
1003                 case Pccp:
1004                         if(ppp->ctype != nil){
1005                                 (*ppp->ctype->fini)(ppp->cstate);
1006                                 ppp->cstate = nil;
1007                         }
1008                         ppp->ctype = ctype;
1009                         if(ctype)
1010                                 ppp->cstate = (*ctype->init)(ppp);
1011                         break;
1012                 case Pipcp:
1013                         if(validv4(ipaddr) && ppp->remotefrozen == 0)
1014                                 ipmove(ppp->remote, ipaddr);
1015                         break;
1016                 }
1017                 p->flags = flags;
1018         }
1019
1020         hnputs(repm->len, BLEN(repb));
1021         printopts(p, repb, 1);
1022         putframe(ppp, p->proto, repb);
1023         freeb(repb);
1024
1025         return rejecting || nacking;
1026 }
1027 static void
1028 dmppkt(char *s, uchar *a, int na)
1029 {
1030         int i;
1031
1032         if (debug < 3)
1033                 return;
1034
1035         fprint(2, "%s", s);
1036         for(i = 0; i < na; i++)
1037                 fprint(2, " %.2ux", a[i]);
1038         fprint(2, "\n");
1039 }
1040
1041 static void
1042 dropoption(Pstate *p, Lcpopt *o)
1043 {
1044         unsigned n = o->type;
1045
1046         switch(n){
1047         case Oipaddr:
1048                 break;
1049         case Oipdns:
1050                 p->optmask &= ~Fipdns;
1051                 break;
1052         case Oipwins:
1053                 p->optmask &= ~Fipwins;
1054                 break;
1055         case Oipdns2:
1056                 p->optmask &= ~Fipdns2;
1057                 break;
1058         case Oipwins2:
1059                 p->optmask &= ~Fipwins2;
1060                 break;
1061         default:
1062                 if(o->type < 8*sizeof(p->optmask))
1063                         p->optmask &= ~(1<<o->type);
1064                 break;
1065         }
1066 }
1067
1068 /*
1069  *  parse configuration rejection, just stop sending anything that they
1070  *  don't like (except for ipcp address nak).
1071  */
1072 static void
1073 rejopts(PPP *ppp, Pstate *p, Block *b, int code)
1074 {
1075         Lcpmsg *m;
1076         Lcpopt *o;
1077         uchar newip[IPaddrlen];
1078
1079         /* just give up trying what the other side doesn't like */
1080         m = (Lcpmsg*)b->rptr;
1081         for(b->rptr = m->data; b->rptr < b->wptr; b->rptr += o->len){
1082                 o = (Lcpopt*)b->rptr;
1083                 if(b->rptr + o->len > b->wptr){
1084                         netlog("ppp: bad roption length %ux\n", o->type);
1085                         return;
1086                 }
1087
1088                 if(code == Lconfrej){
1089                         dropoption(p, o);
1090                         netlog("ppp: %ux rejecting %d\n",
1091                                         p->proto, o->type);
1092                         continue;
1093                 }
1094
1095                 switch(p->proto){
1096                 case Plcp:
1097                         switch(o->type){
1098                         case Octlmap:
1099                                 ppp->rctlmap = nhgetl(o->data);
1100                                 break;
1101                         case Oauth:
1102                                 /* don't allow client to request no auth */
1103                                 /* could try different auth protocol here */
1104                                 fprint(2, "ppp: can not reject CHAP\n");
1105                                 exits("ppp: CHAP");
1106                                 break;
1107                         default:
1108                                 if(o->type < 8*sizeof(p->optmask))
1109                                         p->optmask &= ~(1<<o->type);
1110                                 break;
1111                         };
1112                         break;
1113                 case Pccp:
1114                         switch(o->type){
1115                         default:
1116                                 dropoption(p, o);
1117                                 break;
1118                         }
1119                         break;
1120                 case Pipcp:
1121                         switch(o->type){
1122                         case Oipaddr:
1123 syslog(0, "ppp", "rejected addr %I with %V", ppp->local, o->data);
1124                                 /* if we're a server, don't let other end change our addr */
1125                                 if(ppp->localfrozen){
1126                                         dropoption(p, o);
1127                                         break;
1128                                 }
1129
1130                                 /* accept whatever server tells us */
1131                                 if(!validv4(ppp->local)){
1132                                         v4tov6(ppp->local, o->data);
1133                                         dropoption(p, o);
1134                                         break;
1135                                 }
1136
1137                                 /* if he didn't like our addr, ask for a generic one */
1138                                 v4tov6(newip, o->data);
1139                                 if(!validv4(newip)){
1140                                         invalidate(ppp->local);
1141                                         break;
1142                                 }
1143
1144                                 /* if he gives us something different, use it anyways */
1145                                 v4tov6(ppp->local, o->data);
1146                                 dropoption(p, o);
1147                                 break;
1148                         case Oipdns:
1149                                 if (!validv4(ppp->dns[0])){
1150                                         v4tov6(ppp->dns[0], o->data);
1151                                         dropoption(p, o);
1152                                         break;
1153                                 }
1154                                 v4tov6(newip, o->data);
1155                                 if(!validv4(newip)){
1156                                         invalidate(ppp->dns[0]);
1157                                         break;
1158                                 }
1159                                 v4tov6(ppp->dns[0], o->data);
1160                                 dropoption(p, o);
1161                                 break;
1162                         case Oipwins:
1163                                 if (!validv4(ppp->wins[0])){
1164                                         v4tov6(ppp->wins[0], o->data);
1165                                         dropoption(p, o);
1166                                         break;
1167                                 }
1168                                 v4tov6(newip, o->data);
1169                                 if(!validv4(newip)){
1170                                         invalidate(ppp->wins[0]);
1171                                         break;
1172                                 }
1173                                 v4tov6(ppp->wins[0], o->data);
1174                                 dropoption(p, o);
1175                                 break;
1176                         case Oipdns2:
1177                                 if (!validv4(ppp->dns[1])){
1178                                         v4tov6(ppp->dns[1], o->data);
1179                                         dropoption(p, o);
1180                                         break;
1181                                 }
1182                                 v4tov6(newip, o->data);
1183                                 if(!validv4(newip)){
1184                                         invalidate(ppp->dns[1]);
1185                                         break;
1186                                 }
1187                                 v4tov6(ppp->dns[1], o->data);
1188                                 dropoption(p, o);
1189                                 break;
1190                         case Oipwins2:
1191                                 if (!validv4(ppp->wins[1])){
1192                                         v4tov6(ppp->wins[1], o->data);
1193                                         dropoption(p, o);
1194                                         break;
1195                                 }
1196                                 v4tov6(newip, o->data);
1197                                 if(!validv4(newip)){
1198                                         invalidate(ppp->wins[1]);
1199                                         break;
1200                                 }
1201                                 v4tov6(ppp->wins[1], o->data);
1202                                 dropoption(p, o);
1203                                 break;
1204                         default:
1205                                 dropoption(p, o);
1206                                 break;
1207                         }
1208                         break;
1209                 }
1210         }
1211 }
1212
1213
1214 /*
1215  *  put a messages through the lcp or ipcp state machine.  They are
1216  *  very similar.
1217  */
1218 static void
1219 rcv(PPP *ppp, Pstate *p, Block *b)
1220 {
1221         ulong len;
1222         int err;
1223         Lcpmsg *m;
1224         int proto;
1225
1226         if(BLEN(b) < 4){
1227                 netlog("ppp: short lcp message\n");
1228                 freeb(b);
1229                 return;
1230         }
1231         m = (Lcpmsg*)b->rptr;
1232         len = nhgets(m->len);
1233         if(BLEN(b) < len){
1234                 netlog("ppp: short lcp message\n");
1235                 freeb(b);
1236                 return;
1237         }
1238
1239         netlog("ppp: %ux rcv %d len %ld id %d/%d/%d\n",
1240                 p->proto, m->code, len, m->id, p->confid, p->id);
1241
1242         if(p->proto != Plcp && ppp->lcp->state != Sopened){
1243                 netlog("ppp: non-lcp with lcp not open\n");
1244                 freeb(b);
1245                 return;
1246         }
1247
1248         qlock(ppp);
1249         switch(m->code){
1250         case Lconfreq:
1251                 printopts(p, b, 0);
1252                 err = getopts(ppp, p, b);
1253                 if(err < 0)
1254                         break;
1255
1256                 if(m->id == p->rcvdconfid)
1257                         break;                  /* don't change state for duplicates */
1258
1259                 switch(p->state){
1260                 case Sackrcvd:
1261                         if(err)
1262                                 break;
1263                         newstate(ppp, p, Sopened);
1264                         break;
1265                 case Sclosed:
1266                 case Sopened:
1267                         config(ppp, p, 1);
1268                         if(err == 0)
1269                                 newstate(ppp, p, Sacksent);
1270                         else
1271                                 newstate(ppp, p, Sreqsent);
1272                         break;
1273                 case Sreqsent:
1274                 case Sacksent:
1275                         if(err == 0)
1276                                 newstate(ppp, p, Sacksent);
1277                         else
1278                                 newstate(ppp, p, Sreqsent);
1279                         break;
1280                 }
1281                 break;
1282         case Lconfack:
1283                 if(p->confid != m->id){
1284                         /* ignore if it isn't the message we're sending */
1285                         netlog("ppp: dropping confack\n");
1286                         break;
1287                 }
1288                 p->confid = -1;         /* ignore duplicates */
1289                 p->id++;                /* avoid sending duplicates */
1290
1291                 netlog("ppp: recv confack\n");
1292                 switch(p->state){
1293                 case Sopened:
1294                 case Sackrcvd:
1295                         config(ppp, p, 1);
1296                         newstate(ppp, p, Sreqsent);
1297                         break;
1298                 case Sreqsent:
1299                         newstate(ppp, p, Sackrcvd);
1300                         break;
1301                 case Sacksent:
1302                         newstate(ppp, p, Sopened);
1303                         break;
1304                 }
1305                 break;
1306         case Lconfrej:
1307         case Lconfnak:
1308                 if(p->confid != m->id) {
1309                         /* ignore if it isn't the message we're sending */
1310                         netlog("ppp: dropping confrej or confnak\n");
1311                         break;
1312                 }
1313                 p->confid = -1;         /* ignore duplicates */
1314                 p->id++;                /* avoid sending duplicates */
1315
1316                 switch(p->state){
1317                 case Sopened:
1318                 case Sackrcvd:
1319                         config(ppp, p, 1);
1320                         newstate(ppp, p, Sreqsent);
1321                         break;
1322                 case Sreqsent:
1323                 case Sacksent:
1324                         printopts(p, b, 0);
1325                         rejopts(ppp, p, b, m->code);
1326                         config(ppp, p, 1);
1327                         break;
1328                 }
1329                 break;
1330         case Ltermreq:
1331                 m->code = Ltermack;
1332                 putframe(ppp, p->proto, b);
1333
1334                 switch(p->state){
1335                 case Sackrcvd:
1336                 case Sacksent:
1337                         newstate(ppp, p, Sreqsent);
1338                         break;
1339                 case Sopened:
1340                         newstate(ppp, p, Sclosing);
1341                         break;
1342                 }
1343                 break;
1344         case Ltermack:
1345                 if(p->termid != m->id)  /* ignore if it isn't the message we're sending */
1346                         break;
1347
1348                 if(p->proto == Plcp)
1349                         ppp->ipcp->state = Sclosed;
1350                 switch(p->state){
1351                 case Sclosing:
1352                         newstate(ppp, p, Sclosed);
1353                         break;
1354                 case Sackrcvd:
1355                         newstate(ppp, p, Sreqsent);
1356                         break;
1357                 case Sopened:
1358                         config(ppp, p, 0);
1359                         newstate(ppp, p, Sreqsent);
1360                         break;
1361                 }
1362                 break;
1363         case Lcoderej:
1364                 //newstate(ppp, p, Sclosed);
1365                 syslog(0, LOG, "code reject %d", m->data[0]);
1366                 break;
1367         case Lprotorej:
1368                 proto = nhgets(m->data);
1369                 netlog("ppp: proto reject %ux\n", proto);
1370                 if(proto == Pccp)
1371                         newstate(ppp, ppp->ccp, Sclosed);
1372                 break;
1373         case Lechoreq:
1374                 if(BLEN(b) < 8){
1375                         netlog("ppp: short lcp echo request\n");
1376                         freeb(b);
1377                         return;
1378                 }
1379                 m->code = Lechoack;
1380                 hnputl(m->data, ppp->magic);
1381                 putframe(ppp, p->proto, b);
1382                 break;
1383         case Lechoack:
1384                 p->echoack = 1;
1385                 break;
1386         case Ldiscard:
1387                 /* nothing to do */
1388                 break;
1389         case Lresetreq:
1390                 if(p->proto != Pccp)
1391                         break;
1392                 ppp->stat.compreset++;
1393                 if(ppp->ctype != nil)
1394                         b = (*ppp->ctype->resetreq)(ppp->cstate, b);
1395                 if(b != nil) {
1396                         m = (Lcpmsg*)b->rptr;
1397                         m->code = Lresetack;
1398                         putframe(ppp, p->proto, b);
1399                 }
1400                 break;
1401         case Lresetack:
1402                 if(p->proto != Pccp)
1403                         break;
1404                 if(ppp->unctype != nil)
1405                         (*ppp->unctype->resetack)(ppp->uncstate, b);
1406                 break;
1407         }
1408
1409         qunlock(ppp);
1410         freeb(b);
1411 }
1412
1413 /*
1414  *  timer for protocol state machine
1415  */
1416 static void
1417 ptimer(PPP *ppp, Pstate *p)
1418 {
1419         if(p->state == Sopened || p->state == Sclosed)
1420                 return;
1421
1422         p->timeout--;
1423         switch(p->state){
1424         case Sclosing:
1425                 sendtermreq(ppp, p);
1426                 break;
1427         case Sreqsent:
1428         case Sacksent:
1429                 if(p->timeout <= 0)
1430                         newstate(ppp, p, Sclosed);
1431                 else {
1432                         config(ppp, p, 0);
1433                 }
1434                 break;
1435         case Sackrcvd:
1436                 if(p->timeout <= 0)
1437                         newstate(ppp, p, Sclosed);
1438                 else {
1439                         config(ppp, p, 0);
1440                         newstate(ppp, p, Sreqsent);
1441                 }
1442                 break;
1443         }
1444 }
1445
1446 /* paptimer -- pap timer event handler
1447  *
1448  * If PAP authorization hasn't come through, resend an authreqst.  If
1449  * the maximum number of requests have been sent (~ 30 seconds), give
1450  * up.
1451  *
1452  */
1453 static void
1454 authtimer(PPP* ppp)
1455 {
1456         if(ppp->chap->proto != APpasswd)
1457                 return;
1458
1459         if(ppp->chap->id < 21)
1460                 putpaprequest(ppp);
1461         else {
1462                 terminate(ppp, 0);
1463                 netlog("ppp: pap timed out--not authorized\n");
1464         }
1465 }
1466
1467
1468 /*
1469  *  timer for ppp
1470  */
1471 static void
1472 ppptimer(PPP *ppp)
1473 {
1474         while(!dying){
1475                 sleep(Period);
1476                 qlock(ppp);
1477
1478                 netlog("ppp: ppptimer\n");
1479                 ptimer(ppp, ppp->lcp);
1480                 if(ppp->lcp->state == Sopened) {
1481                         switch(ppp->phase){
1482                         case Pnet:
1483                                 ptimer(ppp, ppp->ccp);
1484                                 ptimer(ppp, ppp->ipcp);
1485                                 break;
1486                         case Pauth:
1487                                 authtimer(ppp);
1488                                 break;
1489                         }
1490                 }
1491
1492                 /* link quality measurement */
1493                 if(ppp->period && --(ppp->timeout) <= 0){
1494                         ppp->timeout = ppp->period;
1495                         putlqm(ppp);
1496                 }
1497
1498                 qunlock(ppp);
1499         }
1500 }
1501
1502 static void
1503 setdefroute(char *net, Ipaddr gate)
1504 {
1505         int fd;
1506         char path[128];
1507
1508         snprint(path, sizeof path, "%s/iproute", net);
1509         fd = open(path, ORDWR);
1510         if(fd < 0)
1511                 return;
1512         fprint(fd, "add 0 0 %I", gate);
1513         close(fd);
1514 }
1515
1516 enum
1517 {
1518         Mofd=   32,
1519 };
1520 struct
1521 {
1522         Lock;
1523
1524         int     fd[Mofd];
1525         int     cfd[Mofd];
1526         int     n;
1527 } old;
1528
1529 static char*
1530 ipopen(PPP *ppp)
1531 {
1532         static int ipinprocpid;
1533         int n, cfd, fd;
1534         char path[128];
1535         char buf[128];
1536
1537         if(ipinprocpid <= 0){
1538                 snprint(path, sizeof path, "%s/ipifc/clone", ppp->net);
1539                 cfd = open(path, ORDWR);
1540                 if(cfd < 0)
1541                         return "can't open ip interface";
1542
1543                 n = read(cfd, buf, sizeof(buf) - 1);
1544                 if(n <= 0){
1545                         close(cfd);
1546                         return "can't open ip interface";
1547                 }
1548                 buf[n] = 0;
1549
1550                 netlog("ppp: setting up IP interface local %I remote %I (valid %d)\n",
1551                         ppp->local, ppp->remote, validv4(ppp->remote));
1552                 if(!validv4(ppp->remote))
1553                         ipmove(ppp->remote, ppp->local);
1554
1555                 snprint(path, sizeof path, "%s/ipifc/%s/data", ppp->net, buf);
1556                 fd = open(path, ORDWR);
1557                 if(fd < 0){
1558                         close(cfd);
1559                         return "can't open ip interface";
1560                 }
1561
1562                 if(fprint(cfd, "bind pkt") < 0)
1563                         return "binding pkt to ip interface";
1564                 if(fprint(cfd, "add %I 255.255.255.255 %I %lud proxy", ppp->local,
1565                         ppp->remote, ppp->mtu-10) < 0){
1566                         close(cfd);
1567                         return "can't set addresses";
1568                 }
1569                 if(primary)
1570                         setdefroute(ppp->net, ppp->remote);
1571                 ppp->ipfd = fd;
1572                 ppp->ipcfd = cfd;
1573
1574                 /* signal main() that ip is configured */
1575                 rendezvous((void*)Rmagic, 0);
1576
1577                 switch(ipinprocpid = rfork(RFPROC|RFMEM|RFNOWAIT)){
1578                 case -1:
1579                         sysfatal("forking ipinproc");
1580                 case 0:
1581                         ipinproc(ppp);
1582                         terminate(ppp, 1);
1583                         _exits(0);
1584                 }
1585         } else {
1586                 /* we may have changed addresses */
1587                 if(ipcmp(ppp->local, ppp->curlocal) != 0 ||
1588                    ipcmp(ppp->remote, ppp->curremote) != 0){
1589                         snprint(buf, sizeof buf, "remove %I 255.255.255.255 %I",
1590                             ppp->curlocal, ppp->curremote);
1591                         if(fprint(ppp->ipcfd, "%s", buf) < 0)
1592                                 syslog(0, "ppp", "can't %s: %r", buf);
1593                         snprint(buf, sizeof buf, "add %I 255.255.255.255 %I %lud proxy",
1594                             ppp->local, ppp->remote, ppp->mtu-10);
1595                         if(fprint(ppp->ipcfd, "%s", buf) < 0)
1596                                 syslog(0, "ppp", "can't %s: %r", buf);
1597                 }
1598                 syslog(0, "ppp", "%I/%I -> %I/%I", ppp->curlocal, ppp->curremote,
1599                    ppp->local, ppp->remote);
1600         }
1601         ipmove(ppp->curlocal, ppp->local);
1602         ipmove(ppp->curremote, ppp->remote);
1603
1604         return nil;
1605 }
1606
1607 /* return next input IP packet */
1608 Block*
1609 pppread(PPP *ppp)
1610 {
1611         Block *b, *reply;
1612         int proto, len;
1613         Lcpmsg *m;
1614
1615         while(!dying){
1616                 b = getframe(ppp, &proto);
1617                 if(b == nil)
1618                         return nil;
1619
1620 Again:
1621                 switch(proto){
1622                 case Plcp:
1623                         rcv(ppp, ppp->lcp, b);
1624                         break;
1625                 case Pccp:
1626                         rcv(ppp, ppp->ccp, b);
1627                         break;
1628                 case Pipcp:
1629                         rcv(ppp, ppp->ipcp, b);
1630                         break;
1631                 case Pip:
1632                         if(ppp->ipcp->state == Sopened)
1633                                 return b;
1634                         netlog("ppp: IP recved: link not up\n");
1635                         freeb(b);
1636                         break;
1637                 case Plqm:
1638                         getlqm(ppp, b);
1639                         break;
1640                 case Pchap:
1641                         getchap(ppp, b);
1642                         break;
1643                 case Ppasswd:
1644                         getpap(ppp, b);
1645                         break;
1646                 case Pvjctcp:
1647                 case Pvjutcp:
1648                         if(ppp->ipcp->state != Sopened){
1649                                 netlog("ppp: VJ tcp recved: link not up\n");
1650                                 freeb(b);
1651                                 break;
1652                         }
1653                         ppp->stat.vjin++;
1654                         b = tcpuncompress(ppp->ctcp, b, proto);
1655                         if(b != nil)
1656                                 return b;
1657                         ppp->stat.vjfail++;
1658                         break;
1659                 case Pcdata:
1660                         ppp->stat.uncomp++;
1661                         if(ppp->ccp->state != Sopened){
1662                                 netlog("ppp: compressed data recved: link not up\n");
1663                                 freeb(b);
1664                                 break;
1665                         }
1666                         if(ppp->unctype == nil) {
1667                                 netlog("ppp: compressed data recved: no compression\n");
1668                                 freeb(b);
1669                                 break;
1670                         }
1671                         len = BLEN(b);
1672                         b = (*ppp->unctype->uncompress)(ppp, b, &proto, &reply);
1673                         if(reply != nil){
1674                                 /* send resetreq */
1675                                 ppp->stat.uncompreset++;
1676                                 putframe(ppp, Pccp, reply);
1677                                 freeb(reply);
1678                         }
1679                         if(b == nil)
1680                                 break;
1681                         ppp->stat.uncompin += len;
1682                         ppp->stat.uncompout += BLEN(b);
1683 /* netlog("ppp: uncompressed frame %ux %d %d (%d uchars)\n", proto, b->rptr[0], b->rptr[1], BLEN(b)); /* */
1684                         goto Again;     
1685                 default:
1686                         syslog(0, LOG, "unknown proto %ux", proto);
1687                         if(ppp->lcp->state == Sopened){
1688                                 /* reject the protocol */
1689                                 b->rptr -= 6;
1690                                 m = (Lcpmsg*)b->rptr;
1691                                 m->code = Lprotorej;
1692                                 m->id = ++ppp->lcp->id;
1693                                 hnputs(m->data, proto);
1694                                 hnputs(m->len, BLEN(b));
1695                                 putframe(ppp, Plcp, b);
1696                         }
1697                         freeb(b);
1698                         break;
1699                 }
1700         }
1701         return nil;
1702 }
1703
1704 /* transmit an IP packet */
1705 int
1706 pppwrite(PPP *ppp, Block *b)
1707 {
1708         int proto;
1709         int len;
1710
1711         qlock(ppp);
1712         /* can't send ip packets till we're established */
1713         if(ppp->ipcp->state != Sopened) {
1714                 qunlock(ppp);
1715                 syslog(0, LOG, "IP write: link not up");
1716                 len = blen(b);
1717                 freeb(b);
1718                 return len;
1719         }
1720
1721         proto = Pip;
1722         ppp->stat.ipsend++;
1723
1724         if(ppp->ipcp->flags & Fipcompress){
1725                 b = compress(ppp->ctcp, b, &proto);
1726                 if(b == nil){
1727                         qunlock(ppp);
1728                         return 0;
1729                 }
1730                 if(proto != Pip)
1731                         ppp->stat.vjout++;
1732         }
1733
1734         if(ppp->ctype != nil) {
1735                 len = blen(b);
1736                 b = (*ppp->ctype->compress)(ppp, proto, b, &proto);
1737                 if(proto == Pcdata) {
1738                         ppp->stat.comp++;
1739                         ppp->stat.compin += len;
1740                         ppp->stat.compout += blen(b);
1741                 }
1742         } 
1743
1744         if(putframe(ppp, proto, b) < 0) {
1745                 qunlock(ppp);
1746                 freeb(b);
1747                 return -1;
1748         }
1749         qunlock(ppp);
1750
1751         len = blen(b);
1752         freeb(b);
1753         return len;
1754 }
1755
1756 static void
1757 terminate(PPP *ppp, int kill)
1758 {
1759         close(ppp->ipfd);
1760         ppp->ipfd = -1;
1761         close(ppp->ipcfd);
1762         ppp->ipcfd = -1;
1763         close(ppp->mediain);
1764         close(ppp->mediaout);
1765         ppp->mediain = -1;
1766         ppp->mediaout = -1;
1767         dying = 1;
1768
1769         if(kill)
1770                 postnote(PNGROUP, getpid(), "die");
1771 }
1772
1773 typedef struct Iphdr Iphdr;
1774 struct Iphdr
1775 {
1776         uchar   vihl;           /* Version and header length */
1777         uchar   tos;            /* Type of service */
1778         uchar   length[2];      /* packet length */
1779         uchar   id[2];          /* Identification */
1780         uchar   frag[2];        /* Fragment information */
1781         uchar   ttl;            /* Time to live */
1782         uchar   proto;          /* Protocol */
1783         uchar   cksum[2];       /* Header checksum */
1784         uchar   src[4];         /* Ip source (uchar ordering unimportant) */
1785         uchar   dst[4];         /* Ip destination (uchar ordering unimportant) */
1786 };
1787
1788 static void
1789 ipinproc(PPP *ppp)
1790 {
1791         Block *b;
1792         int m, n;
1793         Iphdr *ip;
1794
1795         while(!dying){
1796
1797                 b = allocb(Buflen);
1798                 n = read(ppp->ipfd, b->wptr, b->lim-b->wptr);
1799                 if(n < 0)
1800                         break;
1801
1802                 /* trim packet if there's padding (e.g. from ether) */
1803                 ip = (Iphdr*)b->rptr;
1804                 m = nhgets(ip->length);
1805                 if(m < n && m > 0)
1806                         n = m;
1807                 b->wptr += n;
1808
1809                 if(pppwrite(ppp, b) < 0)
1810                         break;
1811         }
1812 }
1813
1814 static void
1815 catchdie(void*, char *msg)
1816 {
1817         if(strstr(msg, "die") != nil)
1818                 noted(NCONT);
1819         else
1820                 noted(NDFLT);
1821 }
1822
1823 static void
1824 hexdump(uchar *a, int na)
1825 {
1826         int i;
1827         char buf[80];
1828
1829         fprint(2, "dump %p %d\n", a, na);
1830         buf[0] = '\0';
1831         for(i=0; i<na; i++){
1832                 sprint(buf+strlen(buf), " %.2ux", a[i]);
1833                 if(i%16 == 7)
1834                         sprint(buf+strlen(buf), " --");
1835                 if(i%16==15){
1836                         sprint(buf+strlen(buf), "\n");
1837                         write(2, buf, strlen(buf));
1838                         buf[0] = '\0';
1839                 }
1840         }
1841         if(i%16){
1842                 sprint(buf+strlen(buf), "\n");
1843                 write(2, buf, strlen(buf));
1844         }
1845 }
1846
1847 static void
1848 mediainproc(PPP *ppp)
1849 {
1850         Block *b;
1851         Ipaddr remote;
1852
1853         notify(catchdie);
1854         while(!dying){
1855                 b = pppread(ppp);
1856                 if(b == nil){
1857                         syslog(0, LOG, "pppread return nil");
1858                         break;
1859                 }
1860                 ppp->stat.iprecv++;
1861                 if(ppp->ipcp->state != Sopened) {
1862                         ppp->stat.iprecvnotup++;
1863                         freeb(b);
1864                         continue;
1865                 }
1866
1867                 if(server) {
1868                         v4tov6(remote, b->rptr+12);
1869                         if(ipcmp(remote, ppp->remote) != 0) {
1870                                 ppp->stat.iprecvbadsrc++;
1871                                 freeb(b);
1872                                 continue;
1873                         }
1874                 }
1875                 if(debug > 1){
1876                         netlog("ip write pkt %p %d\n", b->rptr, blen(b));
1877                         hexdump(b->rptr, blen(b));
1878                 }
1879                 if(write(ppp->ipfd, b->rptr, blen(b)) < 0) {
1880                         syslog(0, LOG, "error writing to pktifc");
1881                         freeb(b);
1882                         break;
1883                 }
1884
1885                 freeb(b);
1886         }
1887
1888         netlog(": remote=%I: ppp shutting down\n", ppp->remote);
1889         syslog(0, LOG, ": remote=%I: ppp shutting down", ppp->remote);
1890         syslog(0, LOG, "\t\tppp send = %lud/%lud recv= %lud/%lud",
1891                 ppp->out.packets, ppp->out.uchars,
1892                 ppp->in.packets, ppp->in.uchars);
1893         syslog(0, LOG, "\t\tip send=%lud", ppp->stat.ipsend);
1894         syslog(0, LOG, "\t\tip recv=%lud notup=%lud badsrc=%lud",
1895                 ppp->stat.iprecv, ppp->stat.iprecvnotup, ppp->stat.iprecvbadsrc);
1896         syslog(0, LOG, "\t\tcompress=%lud in=%lud out=%lud reset=%lud",
1897                 ppp->stat.comp, ppp->stat.compin, ppp->stat.compout, ppp->stat.compreset);
1898         syslog(0, LOG, "\t\tuncompress=%lud in=%lud out=%lud reset=%lud",
1899                 ppp->stat.uncomp, ppp->stat.uncompin, ppp->stat.uncompout,
1900                 ppp->stat.uncompreset);
1901         syslog(0, LOG, "\t\tvjin=%lud vjout=%lud vjfail=%lud", 
1902                 ppp->stat.vjin, ppp->stat.vjout, ppp->stat.vjfail);
1903 }
1904
1905 /*
1906  *  link quality management
1907  */
1908 static void
1909 getlqm(PPP *ppp, Block *b)
1910 {
1911         Qualpkt *p;
1912
1913         p = (Qualpkt*)b->rptr;
1914         if(BLEN(b) == sizeof(Qualpkt)){
1915                 ppp->in.reports++;
1916                 ppp->pout.reports = nhgetl(p->peeroutreports);
1917                 ppp->pout.packets = nhgetl(p->peeroutpackets);
1918                 ppp->pout.uchars = nhgetl(p->peeroutuchars);
1919                 ppp->pin.reports = nhgetl(p->peerinreports);
1920                 ppp->pin.packets = nhgetl(p->peerinpackets);
1921                 ppp->pin.discards = nhgetl(p->peerindiscards);
1922                 ppp->pin.errors = nhgetl(p->peerinerrors);
1923                 ppp->pin.uchars = nhgetl(p->peerinuchars);
1924
1925                 /* save our numbers at time of reception */
1926                 memmove(&ppp->sin, &ppp->in, sizeof(Qualstats));
1927
1928         }
1929         freeb(b);
1930         if(ppp->period == 0)
1931                 putlqm(ppp);
1932
1933 }
1934
1935 static void
1936 putlqm(PPP *ppp)
1937 {
1938         Qualpkt *p;
1939         Block *b;
1940
1941         b = allocb(sizeof(Qualpkt));
1942         b->wptr += sizeof(Qualpkt);
1943         p = (Qualpkt*)b->rptr;
1944         hnputl(p->magic, 0);
1945
1946         /* heresay (what he last told us) */
1947         hnputl(p->lastoutreports, ppp->pout.reports);
1948         hnputl(p->lastoutpackets, ppp->pout.packets);
1949         hnputl(p->lastoutuchars, ppp->pout.uchars);
1950
1951         /* our numbers at time of last reception */
1952         hnputl(p->peerinreports, ppp->sin.reports);
1953         hnputl(p->peerinpackets, ppp->sin.packets);
1954         hnputl(p->peerindiscards, ppp->sin.discards);
1955         hnputl(p->peerinerrors, ppp->sin.errors);
1956         hnputl(p->peerinuchars, ppp->sin.uchars);
1957
1958         /* our numbers now */
1959         hnputl(p->peeroutreports, ppp->out.reports+1);
1960         hnputl(p->peeroutpackets, ppp->out.packets+1);
1961         hnputl(p->peeroutuchars, ppp->out.uchars+53/*hack*/);
1962
1963         putframe(ppp, Plqm, b);
1964         freeb(b);
1965         ppp->out.reports++;
1966 }
1967
1968 /*
1969  * init challenge response dialog
1970  */
1971 static void
1972 chapinit(PPP *ppp)
1973 {
1974         Block *b;
1975         Lcpmsg *m;
1976         Chap *c;
1977         int len;
1978         char *aproto;
1979
1980         getauth(ppp);
1981
1982         c = ppp->chap;
1983         c->id++;
1984
1985         switch(c->proto){
1986         default:
1987                 abort();
1988         case APmd5:
1989                 aproto = "chap";
1990                 break;
1991         case APmschap:
1992                 aproto = "mschap";
1993                 break;
1994         }
1995         if((c->cs = auth_challenge("proto=%q role=server", aproto)) == nil)
1996                 sysfatal("auth_challenge: %r");
1997         syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal);
1998         len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname);
1999         b = alloclcp(Cchallenge, c->id, len, &m);
2000
2001         *b->wptr++ = c->cs->nchal;
2002         memmove(b->wptr, c->cs->chal, c->cs->nchal);
2003         b->wptr += c->cs->nchal;
2004         memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
2005         b->wptr += strlen(ppp->chapname);
2006         hnputs(m->len, len);
2007         putframe(ppp, Pchap, b);
2008         freeb(b);
2009
2010         c->state = Cchalsent;
2011 }
2012
2013 /*
2014  * BUG factotum should do this
2015  */
2016 enum {
2017         MShashlen = 16,
2018         MSresplen = 24,
2019         MSchallen = 8,
2020 };
2021
2022 void
2023 desencrypt(uchar data[8], uchar key[7])
2024 {
2025         ulong ekey[32];
2026
2027         key_setup(key, ekey);
2028         block_cipher(ekey, data, 0);
2029 }
2030
2031 void
2032 nthash(uchar hash[MShashlen], char *passwd)
2033 {
2034         uchar buf[512];
2035         int i;
2036         
2037         for(i=0; *passwd && i<sizeof(buf); passwd++) {
2038                 buf[i++] = *passwd;
2039                 buf[i++] = 0;
2040         }
2041         memset(hash, 0, 16);
2042         md4(buf, i, hash, 0);
2043 }
2044
2045 void
2046 mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
2047 {
2048         int i;
2049         uchar buf[21];
2050         
2051         memset(buf, 0, sizeof(buf));
2052         memcpy(buf, hash, MShashlen);
2053
2054         for(i=0; i<3; i++) {
2055                 memmove(resp+i*MSchallen, chal, MSchallen);
2056                 desencrypt(resp+i*MSchallen, buf+i*7);
2057         }
2058 }
2059
2060 /*
2061  *  challenge response dialog
2062  */
2063 extern  int     _asrdresp(int, uchar*, int);
2064
2065 static void
2066 getchap(PPP *ppp, Block *b)
2067 {
2068         AuthInfo *ai;
2069         Lcpmsg *m;
2070         int len, vlen, i, id, n, nresp;
2071         char md5buf[512], code;
2072         Chap *c;
2073         Chapreply cr;
2074         MSchapreply mscr;
2075         char uid[PATH];
2076         uchar digest[16], *p, *resp, sdigest[SHA1dlen];
2077         uchar mshash[MShashlen], mshash2[MShashlen];
2078         DigestState *s;
2079         uchar msresp[2*MSresplen+1];
2080
2081         m = (Lcpmsg*)b->rptr;
2082         len = nhgets(m->len);
2083         if(BLEN(b) < len){
2084                 syslog(0, LOG, "short chap message");
2085                 freeb(b);
2086                 return;
2087         }
2088
2089         qlock(ppp);
2090
2091         switch(m->code){
2092         case Cchallenge:
2093                 getauth(ppp);
2094
2095                 vlen = m->data[0];
2096                 if(vlen > len - 5) {
2097                         netlog("PPP: chap: bad challenge len\n");
2098                         break;
2099                 }
2100
2101                 id = m->id;
2102                 switch(ppp->chap->proto){
2103                 default:
2104                         abort();
2105                 case APmd5:
2106                         n = strlen(ppp->secret);
2107                         if(n + vlen + 1 > sizeof(md5buf)) {
2108                                 netlog("PPP: chap: bad challenge len\n");
2109                                 goto end;
2110                         }
2111                         md5buf[0] = m->id;
2112                         memcpy(md5buf+1, ppp->secret, n);
2113                         memcpy(md5buf+1+n, m->data+1, vlen);
2114                         md5((uchar*)md5buf, n + vlen + 1, digest, nil);
2115                         resp = digest;
2116                         nresp = 16;
2117                         break;
2118                 case APmschap:
2119                         nthash(mshash, ppp->secret);
2120                         memset(msresp, 0, sizeof msresp);
2121                         mschalresp(msresp+MSresplen, mshash, m->data+1);
2122                         resp = msresp;
2123                         nresp = sizeof msresp;
2124                         nthash(mshash, ppp->secret);
2125                         md4(mshash, 16, mshash2, 0);
2126                         s = sha1(mshash2, 16, 0, 0);
2127                         sha1(mshash2, 16, 0, s);
2128                         sha1(m->data+1, 8, sdigest, s);
2129                         memmove(ppp->key, sdigest, 16);
2130                         break;
2131                 }
2132                 len = 4 + 1 + nresp + strlen(ppp->chapname);
2133                 freeb(b);
2134                 b = alloclcp(Cresponse, id, len, &m);
2135                 *b->wptr++ = nresp;
2136                 memmove(b->wptr, resp, nresp);
2137                 b->wptr += nresp;
2138                 memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
2139                 b->wptr += strlen(ppp->chapname);
2140                 hnputs(m->len, len);
2141                 netlog("PPP: sending response len %d\n", len);
2142                 putframe(ppp, Pchap, b);
2143                 break;
2144         case Cresponse:
2145                 c = ppp->chap;
2146                 vlen = m->data[0];
2147                 if(m->id != c->id) {
2148                         netlog("PPP: chap: bad response id\n");
2149                         break;
2150                 }
2151                 switch(c->proto) {
2152                 default:
2153                         sysfatal("unknown chap protocol: %d", c->proto);
2154                 case APmd5:
2155                         if(vlen > len - 5 || vlen != 16) {
2156                                 netlog("PPP: chap: bad response len\n");
2157                                 break;
2158                         }
2159
2160                         cr.id = m->id;
2161                         memmove(cr.resp, m->data+1, 16);
2162                         memset(uid, 0, sizeof(uid));
2163                         n = len-5-vlen;
2164                         if(n >= PATH)
2165                                 n = PATH-1;
2166                         memmove(uid, m->data+1+vlen, n);
2167                         c->cs->user = uid;
2168                         c->cs->resp = &cr;
2169                         c->cs->nresp = sizeof cr;
2170                         break;
2171                 case APmschap:
2172                         if(vlen > len - 5 || vlen != 49) {
2173                                 netlog("PPP: chap: bad response len\n");
2174                                 break;
2175                         }
2176                         memset(&mscr, 0, sizeof(mscr));
2177                         memmove(mscr.LMresp, m->data+1, 24);
2178                         memmove(mscr.NTresp, m->data+24+1, 24);
2179                         n = len-5-vlen;
2180                         p = m->data+1+vlen;
2181                         /* remove domain name */
2182                         for(i=0; i<n; i++) {
2183                                 if(p[i] == '\\') {
2184                                         p += i+1;
2185                                         n -= i+1;
2186                                         break;
2187                                 }
2188                         }
2189                         if(n >= PATH)
2190                                 n = PATH-1;
2191                         memset(uid, 0, sizeof(uid));
2192                         memmove(uid, p, n);
2193                         c->cs->user = uid;
2194                         c->cs->resp = &mscr;
2195                         c->cs->nresp = sizeof mscr;
2196                         break;
2197                 } 
2198
2199                 syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d", ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp);
2200                 if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){
2201                         c->state = Cunauth;
2202                         code = Cfailure;
2203                         syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s", ppp->remote, uid);
2204                 }else{
2205                         c->state = Cauthok;
2206                         code = Csuccess;
2207                         syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret);
2208                         if(c->proto == APmschap){
2209                                 if(ai->nsecret != sizeof(ppp->key))
2210                                         sysfatal("could not get the encryption key");
2211                                 memmove(ppp->key, ai->secret, sizeof(ppp->key));
2212                         }
2213                 }
2214                 auth_freeAI(ai);
2215                 auth_freechal(c->cs);
2216                 c->cs = nil;
2217                 freeb(b);
2218
2219                 /* send reply */
2220                 len = 4;
2221                 b = alloclcp(code, c->id, len, &m);
2222                 hnputs(m->len, len);
2223                 putframe(ppp, Pchap, b);
2224
2225                 if(c->state == Cauthok) {
2226                         setphase(ppp, Pnet);
2227                 } else {
2228                         /* restart chapp negotiation */
2229                         chapinit(ppp);
2230                 }
2231                 
2232                 break;
2233         case Csuccess:
2234                 netlog("ppp: chap succeeded\n");
2235                 setphase(ppp, Pnet);
2236                 break;
2237         case Cfailure:
2238                 netlog("ppp: chap failed\n");
2239                 terminate(ppp, 0);
2240                 break;
2241         default:
2242                 syslog(0, LOG, "chap code %d?", m->code);
2243                 break;
2244         }
2245 end:
2246         qunlock(ppp);
2247         freeb(b);
2248 }
2249
2250 static void
2251 putpaprequest(PPP *ppp)
2252 {
2253         Block *b;
2254         Lcpmsg *m;
2255         Chap *c;
2256         int len, nlen, slen;
2257
2258         getauth(ppp);
2259
2260         c = ppp->chap;
2261         c->id++;
2262         netlog("PPP: pap: send authreq %d %s %s\n", c->id, ppp->chapname, "****");
2263
2264         nlen = strlen(ppp->chapname);
2265         slen = strlen(ppp->secret);
2266         len = 4 + 1 + nlen + 1 + slen;
2267         b = alloclcp(Pauthreq, c->id, len, &m);
2268
2269         *b->wptr++ = nlen;
2270         memmove(b->wptr, ppp->chapname, nlen);
2271         b->wptr += nlen;
2272         *b->wptr++ = slen;
2273         memmove(b->wptr, ppp->secret, slen);
2274         b->wptr += slen;
2275         hnputs(m->len, len);
2276
2277         putframe(ppp, Ppasswd, b);
2278         freeb(b);
2279 }
2280
2281 static void
2282 papinit(PPP *ppp)
2283 {
2284         ppp->chap->id = 0;
2285         putpaprequest(ppp);
2286 }
2287
2288 static void
2289 getpap(PPP *ppp, Block *b)
2290 {
2291         Lcpmsg *m;
2292         int len;
2293
2294         m = (Lcpmsg*)b->rptr;
2295         len = 4;
2296         if(BLEN(b) < 4 || BLEN(b) < (len = nhgets(m->len))){
2297                 syslog(0, LOG, "short pap message (%zd < %d)", BLEN(b), len);
2298                 freeb(b);
2299                 return;
2300         }
2301         if(len < sizeof(Lcpmsg))
2302                 m->data[0] = 0;
2303
2304         qlock(ppp);
2305         switch(m->code){
2306         case Pauthreq:
2307                 netlog("PPP: pap auth request, not supported\n");
2308                 break;
2309         case Pauthack:
2310                 if(ppp->phase == Pauth
2311                 && ppp->chap->proto == APpasswd
2312                 && m->id <= ppp-> chap->id){
2313                         netlog("PPP: pap succeeded\n");
2314                         setphase(ppp, Pnet);
2315                 }
2316                 break;
2317         case Pauthnak:
2318                 if(ppp->phase == Pauth
2319                 && ppp->chap->proto == APpasswd
2320                 && m->id <= ppp-> chap->id){
2321                         netlog("PPP: pap failed (%d:%.*s)\n",
2322                                 m->data[0], m->data[0], (char*)m->data+1);
2323                         terminate(ppp, 0);
2324                 }
2325                 break;
2326         default:
2327                 netlog("PPP: unknown pap messsage %d\n", m->code);
2328         }
2329         qunlock(ppp);
2330         freeb(b);
2331 }
2332
2333 static void
2334 printopts(Pstate *p, Block *b, int send)
2335 {
2336         Lcpmsg *m;      
2337         Lcpopt *o;
2338         int proto, x, period;
2339         uchar *cp;
2340         char *code, *dir;
2341
2342         m = (Lcpmsg*)b->rptr;
2343         switch(m->code) {
2344         default: code = "<unknown>"; break;
2345         case Lconfreq: code = "confrequest"; break;
2346         case Lconfack: code = "confack"; break;
2347         case Lconfnak: code = "confnak"; break;
2348         case Lconfrej: code = "confreject"; break;
2349         }
2350
2351         if(send)
2352                 dir = "send";
2353         else
2354                 dir = "recv";
2355
2356         netlog("ppp: %s %s: id=%d\n", dir, code, m->id);
2357
2358         for(cp = m->data; cp < b->wptr; cp += o->len){
2359                 o = (Lcpopt*)cp;
2360                 if(cp + o->len > b->wptr){
2361                         netlog("\tbad option length %ux\n", o->type);
2362                         return;
2363                 }
2364
2365                 switch(p->proto){
2366                 case Plcp:
2367                         switch(o->type){
2368                         default:
2369                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2370                                 break;
2371                         case Omtu:
2372                                 netlog("\tmtu = %d\n", nhgets(o->data));
2373                                 break;
2374                         case Octlmap:
2375                                 netlog("\tctlmap = %ux\n", nhgetl(o->data));
2376                                 break;
2377                         case Oauth:
2378                                 netlog("\tauth = %ux", nhgetl(o->data));
2379                                 proto = nhgets(o->data);
2380                                 switch(proto) {
2381                                 default:
2382                                         netlog("unknown auth proto %d\n", proto);
2383                                         break;
2384                                 case Ppasswd:
2385                                         netlog("password\n");
2386                                         break;
2387                                 case Pchap:
2388                                         netlog("chap %ux\n", o->data[2]);
2389                                         break;
2390                                 }
2391                                 break;
2392                         case Oquality:
2393                                 proto = nhgets(o->data);
2394                                 switch(proto) {
2395                                 default:
2396                                         netlog("\tunknown quality proto %d\n", proto);
2397                                         break;
2398                                 case Plqm:
2399                                         x = nhgetl(o->data+2)*10;
2400                                         period = (x+Period-1)/Period;
2401                                         netlog("\tlqm period = %d\n", period);
2402                                         break;
2403                                 }
2404                         case Omagic:
2405                                 netlog("\tmagic = %ux\n", nhgetl(o->data));
2406                                 break;
2407                         case Opc:
2408                                 netlog("\tprotocol compress\n");
2409                                 break;
2410                         case Oac:
2411                                 netlog("\taddr compress\n");
2412                                 break;
2413                         }
2414                         break;
2415                 case Pccp:
2416                         switch(o->type){
2417                         default:
2418                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2419                                 break;
2420                         case Ocoui:     
2421                                 netlog("\tOUI\n");
2422                                 break;
2423                         case Ocstac:
2424                                 netlog("\tstac LZS\n");
2425                                 break;
2426                         case Ocmppc:    
2427                                 netlog("\tMicrosoft PPC len=%d %ux\n", o->len, nhgetl(o->data));
2428                                 break;
2429                         case Octhwack:  
2430                                 netlog("\tThwack\n");
2431                                 break;
2432                         }
2433                         break;
2434                 case Pecp:
2435                         switch(o->type){
2436                         default:
2437                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2438                                 break;
2439                         case Oeoui:     
2440                                 netlog("\tOUI\n");
2441                                 break;
2442                         case Oedese:
2443                                 netlog("\tDES\n");
2444                                 break;
2445                         }
2446                         break;
2447                 case Pipcp:
2448                         switch(o->type){
2449                         default:
2450                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2451                                 break;
2452                         case Oipaddrs:  
2453                                 netlog("\tip addrs - deprecated\n");
2454                                 break;
2455                         case Oipcompress:
2456                                 netlog("\tip compress\n");
2457                                 break;
2458                         case Oipaddr:   
2459                                 netlog("\tip addr %V\n", o->data);
2460                                 break;
2461                         case Oipdns:    
2462                                 netlog("\tdns addr %V\n", o->data);
2463                                 break;
2464                         case Oipwins:   
2465                                 netlog("\twins addr %V\n", o->data);
2466                                 break;
2467                         case Oipdns2:   
2468                                 netlog("\tdns2 addr %V\n", o->data);
2469                                 break;
2470                         case Oipwins2:  
2471                                 netlog("\twins2 addr %V\n", o->data);
2472                                 break;
2473                         }
2474                         break;
2475                 }
2476         }
2477 }
2478
2479 static void
2480 sendtermreq(PPP *ppp, Pstate *p)
2481 {
2482         Block *b;
2483         Lcpmsg *m;
2484
2485         p->termid = ++(p->id);
2486         b = alloclcp(Ltermreq, p->termid, 4, &m);
2487         hnputs(m->len, 4);
2488         putframe(ppp, p->proto, b);
2489         freeb(b);
2490         newstate(ppp, p, Sclosing);
2491 }
2492
2493 static void
2494 sendechoreq(PPP *ppp, Pstate *p)
2495 {
2496         Block *b;
2497         Lcpmsg *m;
2498
2499         p->termid = ++(p->id);
2500         b = alloclcp(Lechoreq, p->id, 4, &m);
2501         hnputs(m->len, 4);
2502         putframe(ppp, p->proto, b);
2503         freeb(b);
2504 }
2505
2506 enum
2507 {
2508         CtrlD   = 0x4,
2509         CtrlE   = 0x5,
2510         CtrlO   = 0xf,
2511         Cr      = 13,
2512         View    = 0x80,
2513 };
2514
2515 int conndone;
2516
2517 static void
2518 xfer(int fd)
2519 {
2520         int i, n;
2521         uchar xbuf[128];
2522
2523         for(;;) {
2524                 n = read(fd, xbuf, sizeof(xbuf));
2525                 if(n < 0)
2526                         break;
2527                 if(conndone)
2528                         break;
2529                 for(i = 0; i < n; i++)
2530                         if(xbuf[i] == Cr)
2531                                 xbuf[i] = ' ';
2532                 write(1, xbuf, n);
2533         }
2534         close(fd);
2535 }
2536
2537 static int
2538 readcr(int fd, char *buf, int nbuf)
2539 {
2540         char c;
2541         int n, tot;
2542
2543         tot = 0;
2544         while((n=read(fd, &c, 1)) == 1){
2545                 if(c == '\n'){
2546                         buf[tot] = 0;
2547                         return tot;
2548                 }
2549                 buf[tot++] = c;
2550                 if(tot == nbuf)
2551                         sysfatal("line too long in readcr");
2552         }
2553         return n;
2554 }
2555
2556 static void
2557 connect(int fd, int cfd)
2558 {
2559         int n, ctl;
2560         char xbuf[128];
2561
2562         if (chatfile) {
2563                 int chatfd, lineno, nb;
2564                 char *buf, *p, *s, response[128];
2565                 Dir *dir;
2566
2567                 if ((chatfd = open(chatfile, OREAD)) < 0)
2568                         sysfatal("cannot open %s: %r", chatfile);
2569
2570                 if ((dir = dirfstat(chatfd)) == nil)
2571                         sysfatal("cannot fstat %s: %r",chatfile);
2572
2573                 buf = (char *)malloc(dir->length + 1);
2574                 assert(buf);
2575
2576                 if ((nb = read(chatfd, buf, dir->length)) < 0)
2577                         sysfatal("cannot read chatfile %s: %r", chatfile);
2578                 assert(nb == dir->length);
2579                 buf[dir->length] = '\0';
2580                 free(dir);
2581                 close(chatfd);
2582
2583                 p = buf;
2584                 lineno = 0;
2585                 for(;;) {
2586                         char *_args[3];
2587
2588                         if ((s = strchr(p, '\n')) == nil)
2589                                 break;
2590                         *s++ = '\0';
2591                 
2592                         lineno++;
2593
2594                         if (*p == '#') {
2595                                 p = s; 
2596                                 continue;
2597                         }
2598
2599                         if (tokenize(p, _args, 3) != 2)
2600                                 sysfatal("invalid line %d (line expected: 'send' 'expect')", 
2601                                                 lineno);
2602
2603                         if (debug)
2604                                 print("sending %s, expecting %s\n", _args[0], _args[1]);
2605
2606                         if(strlen(_args[0])){
2607                                 nb = fprint(fd, "%s\r", _args[0]);
2608                                 assert(nb > 0);
2609                         }
2610
2611                         if (strlen(_args[1]) > 0) {
2612                                 if ((nb = readcr(fd, response, sizeof response-1)) < 0)
2613                                         sysfatal("cannot read response from: %r");
2614
2615                                 if (debug)
2616                                         print("response %s\n", response);
2617
2618                                 if (nb == 0)
2619                                         sysfatal("eof on input?");
2620
2621                                 if (cistrstr(response, _args[1]) == nil)
2622                                         sysfatal("expected %s, got %s", _args[1], response);
2623                         }
2624                         p = s;
2625                 }
2626                 free(buf);
2627                 return;
2628         }
2629
2630         print("Connect to file system now, type ctrl-d when done.\n");
2631         print("...(Use the view or down arrow key to send a break)\n");
2632         print("...(Use ctrl-e to set even parity or ctrl-o for odd)\n");
2633
2634         ctl = open("/dev/consctl", OWRITE);
2635         if(ctl < 0)
2636                 sysfatal("opening consctl");
2637         fprint(ctl, "rawon");
2638
2639         fd = dup(fd, -1);
2640         conndone = 0;
2641         switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
2642         case -1:
2643                 sysfatal("forking xfer");
2644         case 0:
2645                 xfer(fd);
2646                 _exits(nil);
2647         }
2648
2649         for(;;){
2650                 read(0, xbuf, 1);
2651                 switch(xbuf[0]&0xff) {
2652                 case CtrlD:     /* done */
2653                         conndone = 1;
2654                         close(ctl);
2655                         print("\n");
2656                         return;
2657                 case CtrlE:     /* set even parity */
2658                         fprint(cfd, "pe");
2659                         break;
2660                 case CtrlO:     /* set odd parity */
2661                         fprint(cfd, "po");
2662                         break;
2663                 case View:      /* send a break */
2664                         fprint(cfd, "k500");
2665                         break;
2666                 default:
2667                         n = write(fd, xbuf, 1);
2668                         if(n < 0) {
2669                                 errstr(xbuf, sizeof(xbuf));
2670                                 conndone = 1;
2671                                 close(ctl);
2672                                 print("[remote write error (%s)]\n", xbuf);
2673                                 return;
2674                         }
2675                 }
2676         }
2677 }
2678
2679 int interactive;
2680
2681 void
2682 usage(void)
2683 {
2684         fprint(2, "usage: ppp [-CPSacdfu] [-b baud] [-k keyspec] [-m mtu] "
2685                 "[-M chatfile] [-p dev] [-x netmntpt] [-t modemcmd] "
2686                 "[local-addr [remote-addr]]\n");
2687         exits("usage");
2688 }
2689
2690 void
2691 main(int argc, char **argv)
2692 {
2693         int mtu, baud, framing, user, mediain, mediaout, cfd;
2694         Ipaddr ipaddr, remip;
2695         char *dev, *modemcmd;
2696         char net[128];
2697         PPP *ppp;
2698         char buf[128];
2699
2700         rfork(RFREND|RFNOTEG|RFNAMEG);
2701
2702         fmtinstall('I', eipfmt);
2703         fmtinstall('V', eipfmt);
2704         fmtinstall('E', eipfmt);
2705
2706         dev = nil;
2707
2708         invalidate(ipaddr);
2709         invalidate(remip);
2710
2711         mtu = Defmtu;
2712         baud = 0;
2713         framing = 0;
2714         setnetmtpt(net, sizeof(net), nil);
2715         user = 0;
2716         modemcmd = nil;
2717
2718         ARGBEGIN{
2719         case 'a':
2720                 noauth = 1;
2721                 break;
2722         case 'b':
2723                 baud = atoi(EARGF(usage()));
2724                 if(baud < 0)
2725                         baud = 0;
2726                 break;
2727         case 'c':
2728                 nocompress = 1;
2729                 break;
2730         case 'C':
2731                 noipcompress = 1;
2732                 break;
2733         case 'd':
2734                 debug++;
2735                 break;
2736         case 'f':
2737                 framing = 1;
2738                 break;
2739         case 'F':
2740                 pppframing = 0;
2741                 break;
2742         case 'k':
2743                 keyspec = EARGF(usage());
2744                 break;
2745         case 'm':
2746                 mtu = atoi(EARGF(usage()));
2747                 if(mtu < Minmtu)
2748                         mtu = Minmtu;
2749                 if(mtu > Maxmtu)
2750                         mtu = Maxmtu;
2751                 break;
2752         case 'M':
2753                 chatfile = EARGF(usage());
2754                 break;
2755         case 'p':
2756                 dev = EARGF(usage());
2757                 break;
2758         case 'P':
2759                 primary = 1;
2760                 break;
2761         case 'S':
2762                 server = 1;
2763                 break;
2764         case 't':
2765                 modemcmd = EARGF(usage());
2766                 break;
2767         case 'u':
2768                 user = 1;
2769                 break;
2770         case 'x':
2771                 setnetmtpt(net, sizeof net, EARGF(usage()));
2772                 break;
2773         default:
2774                 fprint(2, "unknown option %c\n", ARGC());
2775                 usage();
2776         }ARGEND;
2777
2778         switch(argc){
2779         case 2:
2780                 if (parseip(remip, argv[1]) == -1)
2781                         sysfatal("bad remote ip %s", argv[1]);
2782         case 1:
2783                 if (parseip(ipaddr, argv[0]) == -1)
2784                         sysfatal("bad ip %s", argv[0]);
2785         case 0:
2786                 break;
2787         default:
2788                 usage();
2789         }
2790
2791         nip = nipifcs(net);
2792         if(nip == 0 && !server)
2793                 primary = 1;
2794
2795         if(dev != nil){
2796                 mediain = open(dev, ORDWR);
2797                 if(mediain < 0){
2798                         if(strchr(dev, '!')){
2799                                 if((mediain = dial(dev, 0, 0, &cfd)) == -1){
2800                                         fprint(2, "ppp: couldn't dial %s: %r\n", dev);
2801                                         exits(dev);
2802                                 }
2803                         } else {
2804                                 fprint(2, "ppp: couldn't open %s\n", dev);
2805                                 exits(dev);
2806                         }
2807                 } else {
2808                         snprint(buf, sizeof buf, "%sctl", dev);
2809                         cfd = open(buf, ORDWR);
2810                 }
2811                 if(cfd > 0){
2812                         if(baud)
2813                                 fprint(cfd, "b%d", baud);
2814                         fprint(cfd, "m1");      /* cts/rts flow control (and fifo's) on */
2815                         fprint(cfd, "q64000");  /* increase q size to 64k */
2816                         fprint(cfd, "n1");      /* nonblocking writes on */
2817                         fprint(cfd, "r1");      /* rts on */
2818                         fprint(cfd, "d1");      /* dtr on */
2819                         fprint(cfd, "c1");      /* dcdhup on */
2820                         if(user || chatfile)
2821                                 connect(mediain, cfd);
2822                         close(cfd);
2823                 } else {
2824                         if(user || chatfile)
2825                                 connect(mediain, -1);
2826                 }
2827                 mediaout = mediain;
2828         } else {
2829                 mediain = open("/fd/0", OREAD);
2830                 if(mediain < 0){
2831                         fprint(2, "ppp: couldn't open /fd/0\n");
2832                         exits("/fd/0");
2833                 }
2834                 mediaout = open("/fd/1", OWRITE);
2835                 if(mediaout < 0){
2836                         fprint(2, "ppp: couldn't open /fd/0\n");
2837                         exits("/fd/1");
2838                 }
2839         }
2840
2841         if(modemcmd != nil && mediaout >= 0)
2842                 fprint(mediaout, "%s\r", modemcmd);
2843
2844         ppp = mallocz(sizeof(*ppp), 1);
2845         pppopen(ppp, mediain, mediaout, net, ipaddr, remip, mtu, framing);
2846
2847         /* wait until ip is configured */
2848         rendezvous((void*)Rmagic, 0);
2849
2850         if(primary){
2851                 /* create a /net/ndb entry */
2852                 putndb(ppp, net);
2853         }
2854
2855         exits(0);
2856 }
2857
2858 void
2859 netlog(char *fmt, ...)
2860 {
2861         va_list arg;
2862         char *m;
2863         static long start;
2864         long now;
2865
2866         if(debug == 0)
2867                 return;
2868
2869         now = time(0);
2870         if(start == 0)
2871                 start = now;
2872
2873         va_start(arg, fmt);
2874         m = vsmprint(fmt, arg);
2875         fprint(2, "%ld %s", now-start, m);
2876         free(m);
2877         va_end(arg);
2878 }
2879
2880 /*
2881  *  return non-zero if this is a valid v4 address
2882  */
2883 static int
2884 validv4(Ipaddr addr)
2885 {
2886         return memcmp(addr, v4prefix, IPv4off) == 0 && memcmp(addr, v4prefix, IPaddrlen) != 0;
2887 }
2888
2889 static void
2890 invalidate(Ipaddr addr)
2891 {
2892         ipmove(addr, IPnoaddr);
2893 }
2894
2895 /*
2896  *  return number of networks
2897  */
2898 static int
2899 nipifcs(char *net)
2900 {
2901         static Ipifc *ifc;
2902         Ipifc *nifc;
2903         Iplifc *lifc;
2904         int n;
2905
2906         n = 0;
2907         ifc = readipifc(net, ifc, -1);
2908         for(nifc = ifc; nifc != nil; nifc = nifc->next)
2909                 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
2910                         n++;
2911         return n;
2912 }
2913
2914 /*
2915  *   make an ndb entry and put it into /net/ndb for the servers to see
2916  */
2917 static void
2918 putndb(PPP *ppp, char *net)
2919 {
2920         char buf[1024];
2921         char file[64];
2922         char *p, *e;
2923         int fd;
2924
2925         e = buf + sizeof(buf);
2926         p = buf;
2927         p = seprint(p, e, "ip=%I ipmask=255.255.255.255 ipgw=%I\n", ppp->local,
2928                         ppp->remote);
2929         if(validv4(ppp->dns[0]))
2930                 p = seprint(p, e, "\tdns=%I\n", ppp->dns[0]);
2931         if(validv4(ppp->dns[1]))
2932                 p = seprint(p, e, "\tdns=%I\n", ppp->dns[1]);
2933         if(validv4(ppp->wins[0]))
2934                 p = seprint(p, e, "\twins=%I\n", ppp->wins[0]);
2935         if(validv4(ppp->wins[1]))
2936                 p = seprint(p, e, "\twins=%I\n", ppp->wins[1]);
2937         seprint(file, file+sizeof file, "%s/ndb", net);
2938         fd = open(file, OWRITE);
2939         if(fd < 0)
2940                 return;
2941         write(fd, buf, p-buf);
2942         close(fd);
2943         seprint(file, file+sizeof file, "%s/cs", net);
2944         fd = open(file, OWRITE);
2945         write(fd, "refresh", 7);
2946         close(fd);
2947         seprint(file, file+sizeof file, "%s/dns", net);
2948         fd = open(file, OWRITE);
2949         write(fd, "refresh", 7);
2950         close(fd);
2951 }
2952
2953 static void
2954 getauth(PPP *ppp)
2955 {
2956         UserPasswd *up;
2957
2958         if(*ppp->chapname)
2959                 return;
2960
2961         up = auth_getuserpasswd(auth_getkey,"proto=pass service=ppp %s", keyspec);
2962         if(up != nil){
2963                 strcpy(ppp->chapname, up->user);
2964                 strcpy(ppp->secret, up->passwd);
2965         }               
2966 }