1 /* $OpenBSD: cbcp.c,v 1.10 2024/08/09 05:16:13 deraadt Exp $ */
2
3 /*
4 * cbcp - Call Back Configuration Protocol.
5 *
6 * Copyright (c) 1995 Pedro Roque Marques. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The name(s) of the authors of this software must not be used to
21 * endorse or promote products derived from this software without
22 * prior written permission.
23 *
24 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
25 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
26 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
27 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
28 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
29 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
30 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <syslog.h>
38
39 #include "pppd.h"
40 #include "cbcp.h"
41 #include "fsm.h"
42 #include "lcp.h"
43 #include "ipcp.h"
44
45 /*
46 * Protocol entry points.
47 */
48 static void cbcp_init(int unit);
49 static void cbcp_open(int unit);
50 static void cbcp_lowerup(int unit);
51 static void cbcp_input(int unit, u_char *pkt, int len);
52 static void cbcp_protrej(int unit);
53 static int cbcp_printpkt(u_char *pkt, int len,
54 void (*printer)(void *, char *, ...), void *arg);
55
56 struct protent cbcp_protent = {
57 PPP_CBCP,
58 cbcp_init,
59 cbcp_input,
60 cbcp_protrej,
61 cbcp_lowerup,
62 NULL,
63 cbcp_open,
64 NULL,
65 cbcp_printpkt,
66 NULL,
67 0,
68 "CBCP",
69 NULL,
70 NULL,
71 NULL
72 };
73
74 cbcp_state cbcp[NUM_PPP];
75
76 /* internal prototypes */
77
78 static void cbcp_recvreq(cbcp_state *us, char *pckt, int len);
79 static void cbcp_resp(cbcp_state *us);
80 static void cbcp_up(cbcp_state *us);
81 static void cbcp_recvack(cbcp_state *us, char *pckt, int len);
82 static void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len);
83
84 /* init state */
85 static void
cbcp_init(int iface)86 cbcp_init(int iface)
87 {
88 cbcp_state *us;
89
90 us = &cbcp[iface];
91 memset(us, 0, sizeof(cbcp_state));
92 us->us_unit = iface;
93 us->us_type |= (1 << CB_CONF_NO);
94 }
95
96 /* lower layer is up */
97 static void
cbcp_lowerup(int iface)98 cbcp_lowerup(int iface)
99 {
100 cbcp_state *us = &cbcp[iface];
101
102 syslog(LOG_DEBUG, "cbcp_lowerup");
103 syslog(LOG_DEBUG, "want: %d", us->us_type);
104
105 if (us->us_type == CB_CONF_USER)
106 syslog(LOG_DEBUG, "phone no: %s", us->us_number);
107 }
108
109 static void
cbcp_open(int unit)110 cbcp_open(int unit)
111 {
112 syslog(LOG_DEBUG, "cbcp_open");
113 }
114
115 /* process an incoming packet */
116 static void
cbcp_input(int unit,u_char * inpacket,int pktlen)117 cbcp_input(int unit, u_char *inpacket, int pktlen)
118 {
119 u_char *inp;
120 u_char code, id;
121 u_short len;
122
123 cbcp_state *us = &cbcp[unit];
124
125 inp = inpacket;
126
127 if (pktlen < CBCP_MINLEN) {
128 syslog(LOG_ERR, "CBCP packet is too small");
129 return;
130 }
131
132 GETCHAR(code, inp);
133 GETCHAR(id, inp);
134 GETSHORT(len, inp);
135
136 if (len < CBCP_MINLEN || len > pktlen) {
137 syslog(LOG_ERR, "CBCP packet: invalid length");
138 return;
139 }
140 len -= CBCP_MINLEN;
141
142 switch(code) {
143 case CBCP_REQ:
144 us->us_id = id;
145 cbcp_recvreq(us, inp, len);
146 break;
147
148 case CBCP_RESP:
149 syslog(LOG_DEBUG, "CBCP_RESP received");
150 break;
151
152 case CBCP_ACK:
153 if (id != us->us_id)
154 syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
155 us->us_id, id);
156
157 cbcp_recvack(us, inp, len);
158 break;
159
160 default:
161 break;
162 }
163 }
164
165 /* protocol was rejected by foe */
cbcp_protrej(int iface)166 void cbcp_protrej(int iface)
167 {
168 }
169
170 char *cbcp_codenames[] = {
171 "Request", "Response", "Ack"
172 };
173
174 char *cbcp_optionnames[] = {
175 "NoCallback",
176 "UserDefined",
177 "AdminDefined",
178 "List"
179 };
180
181 /* pretty print a packet */
182 static int
cbcp_printpkt(u_char * p,int plen,void (* printer)(void *,char *,...),void * arg)183 cbcp_printpkt(u_char *p, int plen, void (*printer)(void *, char *, ...),
184 void *arg)
185 {
186 int code, opt, id, len, olen, delay;
187 u_char *pstart;
188
189 if (plen < HEADERLEN)
190 return 0;
191 pstart = p;
192 GETCHAR(code, p);
193 GETCHAR(id, p);
194 GETSHORT(len, p);
195 if (len < HEADERLEN || len > plen)
196 return 0;
197
198 if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
199 printer(arg, " %s", cbcp_codenames[code-1]);
200 else
201 printer(arg, " code=0x%x", code);
202
203 printer(arg, " id=0x%x", id);
204 len -= HEADERLEN;
205
206 switch (code) {
207 case CBCP_REQ:
208 case CBCP_RESP:
209 case CBCP_ACK:
210 while(len >= 2) {
211 GETCHAR(opt, p);
212 GETCHAR(olen, p);
213
214 if (olen < 2 || olen > len) {
215 break;
216 }
217
218 printer(arg, " <");
219 len -= olen;
220
221 if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
222 printer(arg, " %s", cbcp_optionnames[opt-1]);
223 else
224 printer(arg, " option=0x%x", opt);
225
226 if (olen > 2) {
227 GETCHAR(delay, p);
228 printer(arg, " delay = %d", delay);
229 }
230
231 if (olen > 3) {
232 int addrt;
233 char str[256];
234
235 GETCHAR(addrt, p);
236 memcpy(str, p, olen - 4);
237 str[olen - 4] = 0;
238 printer(arg, " number = %s", str);
239 }
240 printer(arg, ">");
241 break;
242 }
243
244 default:
245 break;
246 }
247
248 for (; len > 0; --len) {
249 GETCHAR(code, p);
250 printer(arg, " %.2x", code);
251 }
252
253 return p - pstart;
254 }
255
256 /* received CBCP request */
257 static void
cbcp_recvreq(cbcp_state * us,char * pckt,int pcktlen)258 cbcp_recvreq(cbcp_state *us, char *pckt, int pcktlen)
259 {
260 u_char type, opt_len, delay, addr_type;
261 char address[256];
262 int len = pcktlen;
263
264 address[0] = 0;
265
266 while (len > 1) {
267 syslog(LOG_DEBUG, "length: %d", len);
268
269 GETCHAR(type, pckt);
270 GETCHAR(opt_len, pckt);
271
272 if (len < opt_len)
273 break;
274 len -= opt_len;
275
276 if (opt_len > 2)
277 GETCHAR(delay, pckt);
278
279 us->us_allowed |= (1 << type);
280
281 switch(type) {
282 case CB_CONF_NO:
283 syslog(LOG_DEBUG, "no callback allowed");
284 break;
285
286 case CB_CONF_USER:
287 syslog(LOG_DEBUG, "user callback allowed");
288 if (opt_len > 4) {
289 GETCHAR(addr_type, pckt);
290 memcpy(address, pckt, opt_len - 4);
291 address[opt_len - 4] = 0;
292 if (address[0])
293 syslog(LOG_DEBUG, "address: %s", address);
294 }
295 break;
296
297 case CB_CONF_ADMIN:
298 syslog(LOG_DEBUG, "user admin defined allowed");
299 break;
300
301 case CB_CONF_LIST:
302 break;
303 }
304 }
305
306 cbcp_resp(us);
307 }
308
309 static void
cbcp_resp(cbcp_state * us)310 cbcp_resp(cbcp_state *us)
311 {
312 u_char cb_type;
313 u_char buf[256];
314 u_char *bufp = buf;
315 int len = 0;
316
317 cb_type = us->us_allowed & us->us_type;
318 syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
319
320 #if 0
321 if (!cb_type)
322 lcp_down(us->us_unit);
323 #endif
324
325 if (cb_type & ( 1 << CB_CONF_USER ) ) {
326 syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
327 PUTCHAR(CB_CONF_USER, bufp);
328 len = 3 + 1 + strlen(us->us_number) + 1;
329 PUTCHAR(len , bufp);
330 PUTCHAR(5, bufp); /* delay */
331 PUTCHAR(1, bufp);
332 BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
333 cbcp_send(us, CBCP_RESP, buf, len);
334 return;
335 }
336
337 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
338 syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
339 PUTCHAR(CB_CONF_ADMIN, bufp);
340 len = 3 + 1;
341 PUTCHAR(len , bufp);
342 PUTCHAR(5, bufp); /* delay */
343 PUTCHAR(0, bufp);
344 cbcp_send(us, CBCP_RESP, buf, len);
345 return;
346 }
347
348 if (cb_type & ( 1 << CB_CONF_NO ) ) {
349 syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
350 PUTCHAR(CB_CONF_NO, bufp);
351 len = 3;
352 PUTCHAR(len , bufp);
353 PUTCHAR(0, bufp);
354 cbcp_send(us, CBCP_RESP, buf, len);
355 (*ipcp_protent.open)(us->us_unit);
356 return;
357 }
358 }
359
360 static void
cbcp_send(cbcp_state * us,u_char code,u_char * buf,int len)361 cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len)
362 {
363 u_char *outp;
364 int outlen;
365
366 outp = outpacket_buf;
367
368 outlen = 4 + len;
369
370 MAKEHEADER(outp, PPP_CBCP);
371
372 PUTCHAR(code, outp);
373 PUTCHAR(us->us_id, outp);
374 PUTSHORT(outlen, outp);
375
376 if (len)
377 BCOPY(buf, outp, len);
378
379 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
380 }
381
382 static void
cbcp_recvack(cbcp_state * us,char * pckt,int len)383 cbcp_recvack(cbcp_state *us, char *pckt, int len)
384 {
385 u_char type, delay, addr_type;
386 int opt_len;
387 char address[256];
388
389 if (len > 1) {
390 GETCHAR(type, pckt);
391 GETCHAR(opt_len, pckt);
392
393 if (opt_len > len)
394 return;
395
396 if (opt_len > 2)
397 GETCHAR(delay, pckt);
398
399 if (opt_len > 4) {
400 GETCHAR(addr_type, pckt);
401 memcpy(address, pckt, opt_len - 4);
402 address[opt_len - 4] = 0;
403 if (address[0])
404 syslog(LOG_DEBUG, "peer will call: %s", address);
405 }
406 }
407
408 cbcp_up(us);
409 }
410
411 extern volatile sig_atomic_t persist;
412
413 /* ok peer will do callback */
414 static void
cbcp_up(cbcp_state * us)415 cbcp_up(cbcp_state *us)
416 {
417 persist = 0;
418 lcp_close(0, "Call me back, please");
419 }
420