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 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 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 110 cbcp_open(int unit) 111 { 112 syslog(LOG_DEBUG, "cbcp_open"); 113 } 114 115 /* process an incoming packet */ 116 static void 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 */ 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 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 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 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 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 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 415 cbcp_up(cbcp_state *us) 416 { 417 persist = 0; 418 lcp_close(0, "Call me back, please"); 419 } 420