1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <sys/time.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 38 #include <assert.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <md5.h> 43 #include <netdb.h> 44 #include <stdarg.h> 45 #include <stddef.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include <security/pam_appl.h> 52 #include <security/openpam.h> 53 54 #include "taclib_private.h" 55 56 static int add_str_8(struct tac_handle *, u_int8_t *, 57 struct tac_str *); 58 static int add_str_16(struct tac_handle *, u_int16_t *, 59 struct tac_str *); 60 static int protocol_version(int, int, int); 61 static void close_connection(struct tac_handle *); 62 static int conn_server(struct tac_handle *); 63 static void crypt_msg(struct tac_handle *, struct tac_msg *); 64 static void *dup_str(struct tac_handle *, const struct tac_str *, 65 size_t *); 66 static int establish_connection(struct tac_handle *); 67 static void free_str(struct tac_str *); 68 static void generr(struct tac_handle *, const char *, ...) 69 __printflike(2, 3); 70 static void gen_session_id(struct tac_msg *); 71 static int get_srvr_end(struct tac_handle *); 72 static int get_str(struct tac_handle *, const char *, 73 struct tac_str *, size_t); 74 static void init_str(struct tac_str *); 75 static int read_timed(struct tac_handle *, void *, size_t, 76 const struct timeval *); 77 static int recv_msg(struct tac_handle *); 78 static int save_str(struct tac_handle *, struct tac_str *, 79 const void *, size_t); 80 static int send_msg(struct tac_handle *); 81 static int split(char *, char *[], int, char *, size_t); 82 static void *xmalloc(struct tac_handle *, size_t); 83 static char *xstrdup(struct tac_handle *, const char *); 84 static void clear_srvr_avs(struct tac_handle *); 85 static void create_msg(struct tac_handle *, int, int, int); 86 87 /* 88 * Append some optional data to the current request, and store its 89 * length into the 8-bit field referenced by "fld". Returns 0 on 90 * success, or -1 on failure. 91 * 92 * This function also frees the "cs" string data and initializes it 93 * for the next time. 94 */ 95 static int 96 add_str_8(struct tac_handle *h, u_int8_t *fld, struct tac_str *cs) 97 { 98 u_int16_t len; 99 100 if (add_str_16(h, &len, cs) == -1) 101 return -1; 102 len = ntohs(len); 103 if (len > 0xff) { 104 generr(h, "Field too long"); 105 return -1; 106 } 107 *fld = len; 108 return 0; 109 } 110 111 /* 112 * Append some optional data to the current request, and store its 113 * length into the 16-bit field (network byte order) referenced by 114 * "fld". Returns 0 on success, or -1 on failure. 115 * 116 * This function also frees the "cs" string data and initializes it 117 * for the next time. 118 */ 119 static int 120 add_str_16(struct tac_handle *h, u_int16_t *fld, struct tac_str *cs) 121 { 122 size_t len; 123 124 len = cs->len; 125 if (cs->data == NULL) 126 len = 0; 127 if (len != 0) { 128 int offset; 129 130 if (len > 0xffff) { 131 generr(h, "Field too long"); 132 return -1; 133 } 134 offset = ntohl(h->request.length); 135 if (offset + len > BODYSIZE) { 136 generr(h, "Message too long"); 137 return -1; 138 } 139 memcpy(h->request.u.body + offset, cs->data, len); 140 h->request.length = htonl(offset + len); 141 } 142 *fld = htons(len); 143 free_str(cs); 144 return 0; 145 } 146 147 static int 148 protocol_version(int msg_type, int var, int type) 149 { 150 int minor; 151 152 switch (msg_type) { 153 case TAC_AUTHEN: 154 /* 'var' represents the 'action' */ 155 switch (var) { 156 case TAC_AUTHEN_LOGIN: 157 switch (type) { 158 159 case TAC_AUTHEN_TYPE_PAP: 160 case TAC_AUTHEN_TYPE_CHAP: 161 case TAC_AUTHEN_TYPE_MSCHAP: 162 case TAC_AUTHEN_TYPE_ARAP: 163 minor = 1; 164 break; 165 166 default: 167 minor = 0; 168 break; 169 } 170 break; 171 172 case TAC_AUTHEN_SENDAUTH: 173 minor = 1; 174 break; 175 176 default: 177 minor = 0; 178 break; 179 }; 180 break; 181 182 case TAC_AUTHOR: 183 /* 'var' represents the 'method' */ 184 switch (var) { 185 /* 186 * When new authentication methods are added, include 'method' 187 * in determining the value of 'minor'. At this point, all 188 * methods defined in this implementation (see "Authorization 189 * authentication methods" in taclib.h) are minor version 0 190 * Not all types, however, indicate minor version 0. 191 */ 192 case TAC_AUTHEN_METH_NOT_SET: 193 case TAC_AUTHEN_METH_NONE: 194 case TAC_AUTHEN_METH_KRB5: 195 case TAC_AUTHEN_METH_LINE: 196 case TAC_AUTHEN_METH_ENABLE: 197 case TAC_AUTHEN_METH_LOCAL: 198 case TAC_AUTHEN_METH_TACACSPLUS: 199 case TAC_AUTHEN_METH_RCMD: 200 switch (type) { 201 case TAC_AUTHEN_TYPE_PAP: 202 case TAC_AUTHEN_TYPE_CHAP: 203 case TAC_AUTHEN_TYPE_MSCHAP: 204 case TAC_AUTHEN_TYPE_ARAP: 205 minor = 1; 206 break; 207 208 default: 209 minor = 0; 210 break; 211 } 212 break; 213 default: 214 minor = 0; 215 break; 216 } 217 break; 218 219 case TAC_ACCT: 220 221 default: 222 minor = 0; 223 break; 224 } 225 226 return TAC_VER_MAJOR << 4 | minor; 227 } 228 229 230 static void 231 close_connection(struct tac_handle *h) 232 { 233 if (h->fd != -1) { 234 close(h->fd); 235 h->fd = -1; 236 } 237 } 238 239 static int 240 conn_server(struct tac_handle *h) 241 { 242 struct tac_server *srvp = &h->servers[h->cur_server]; 243 int flags; 244 245 if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { 246 generr(h, "Cannot create socket: %s", strerror(errno)); 247 return -1; 248 } 249 if ((flags = fcntl(h->fd, F_GETFL, 0)) == -1 || 250 fcntl(h->fd, F_SETFL, flags | O_NONBLOCK) == -1) { 251 generr(h, "Cannot set non-blocking mode on socket: %s", 252 strerror(errno)); 253 close(h->fd); 254 h->fd = -1; 255 return -1; 256 } 257 if (connect(h->fd, (struct sockaddr *)&srvp->addr, 258 sizeof srvp->addr) == 0) 259 return 0; 260 261 if (errno == EINPROGRESS) { 262 fd_set wfds; 263 struct timeval tv; 264 int nfds; 265 struct sockaddr peer; 266 socklen_t errlen, peerlen; 267 int err; 268 269 /* Wait for the connection to complete. */ 270 FD_ZERO(&wfds); 271 FD_SET(h->fd, &wfds); 272 tv.tv_sec = srvp->timeout; 273 tv.tv_usec = 0; 274 nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv); 275 if (nfds == -1) { 276 generr(h, "select: %s", strerror(errno)); 277 close(h->fd); 278 h->fd = -1; 279 return -1; 280 } 281 if (nfds == 0) { 282 generr(h, "connect: timed out"); 283 close(h->fd); 284 h->fd = -1; 285 return -1; 286 } 287 288 /* See whether we are connected now. */ 289 peerlen = sizeof peer; 290 if (getpeername(h->fd, &peer, &peerlen) == 0) 291 return 0; 292 293 if (errno != ENOTCONN) { 294 generr(h, "getpeername: %s", strerror(errno)); 295 close(h->fd); 296 h->fd = -1; 297 return -1; 298 } 299 300 /* Find out why the connect failed. */ 301 errlen = sizeof err; 302 getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen); 303 errno = err; 304 } 305 generr(h, "connect: %s", strerror(errno)); 306 close(h->fd); 307 h->fd = -1; 308 return -1; 309 } 310 311 /* 312 * Encrypt or decrypt a message. The operations are symmetrical. 313 */ 314 static void 315 crypt_msg(struct tac_handle *h, struct tac_msg *msg) 316 { 317 const char *secret; 318 MD5_CTX base_ctx; 319 MD5_CTX ctx; 320 unsigned char md5[16]; 321 int chunk; 322 int msg_len; 323 324 secret = h->servers[h->cur_server].secret; 325 if (secret[0] == '\0') 326 msg->flags |= TAC_UNENCRYPTED; 327 if (msg->flags & TAC_UNENCRYPTED) 328 return; 329 330 msg_len = ntohl(msg->length); 331 332 MD5Init(&base_ctx); 333 MD5Update(&base_ctx, msg->session_id, sizeof msg->session_id); 334 MD5Update(&base_ctx, secret, strlen(secret)); 335 MD5Update(&base_ctx, &msg->version, sizeof msg->version); 336 MD5Update(&base_ctx, &msg->seq_no, sizeof msg->seq_no); 337 338 ctx = base_ctx; 339 for (chunk = 0; chunk < msg_len; chunk += sizeof md5) { 340 int chunk_len; 341 int i; 342 343 MD5Final(md5, &ctx); 344 345 if ((chunk_len = msg_len - chunk) > sizeof md5) 346 chunk_len = sizeof md5; 347 for (i = 0; i < chunk_len; i++) 348 msg->u.body[chunk + i] ^= md5[i]; 349 350 ctx = base_ctx; 351 MD5Update(&ctx, md5, sizeof md5); 352 } 353 } 354 355 /* 356 * Return a dynamically allocated copy of the given server string. 357 * The copy is null-terminated. If "len" is non-NULL, the length of 358 * the string (excluding the terminating null byte) is stored via it. 359 * Returns NULL on failure. Empty strings are still allocated even 360 * though they have no content. 361 */ 362 static void * 363 dup_str(struct tac_handle *h, const struct tac_str *ss, size_t *len) 364 { 365 unsigned char *p; 366 367 if ((p = (unsigned char *)xmalloc(h, ss->len + 1)) == NULL) 368 return NULL; 369 if (ss->data != NULL && ss->len != 0) 370 memcpy(p, ss->data, ss->len); 371 p[ss->len] = '\0'; 372 if (len != NULL) 373 *len = ss->len; 374 return p; 375 } 376 377 static int 378 establish_connection(struct tac_handle *h) 379 { 380 int i; 381 382 if (h->fd >= 0) /* Already connected. */ 383 return 0; 384 if (h->num_servers == 0) { 385 generr(h, "No TACACS+ servers specified"); 386 return -1; 387 } 388 /* 389 * Try the servers round-robin. We begin with the one that 390 * worked for us the last time. That way, once we find a good 391 * server, we won't waste any more time trying the bad ones. 392 */ 393 for (i = 0; i < h->num_servers; i++) { 394 if (conn_server(h) == 0) { 395 h->single_connect = (h->servers[h->cur_server].flags & 396 TAC_SRVR_SINGLE_CONNECT) != 0; 397 return 0; 398 } 399 if (++h->cur_server >= h->num_servers) /* Wrap around */ 400 h->cur_server = 0; 401 } 402 /* Just return whatever error was last reported by conn_server(). */ 403 return -1; 404 } 405 406 /* 407 * Free a client string, obliterating its contents first for security. 408 */ 409 static void 410 free_str(struct tac_str *cs) 411 { 412 if (cs->data != NULL) { 413 memset_s(cs->data, cs->len, 0, cs->len); 414 free(cs->data); 415 cs->data = NULL; 416 cs->len = 0; 417 } 418 } 419 420 static void 421 generr(struct tac_handle *h, const char *format, ...) 422 { 423 va_list ap; 424 425 va_start(ap, format); 426 vsnprintf(h->errmsg, ERRSIZE, format, ap); 427 va_end(ap); 428 } 429 430 static void 431 gen_session_id(struct tac_msg *msg) 432 { 433 int r; 434 435 r = arc4random(); 436 msg->session_id[0] = r >> 8; 437 msg->session_id[1] = r; 438 r = arc4random(); 439 msg->session_id[2] = r >> 8; 440 msg->session_id[3] = r; 441 } 442 443 /* 444 * Verify that we are exactly at the end of the response message. 445 * Returns 0 on success, -1 on failure. 446 */ 447 static int 448 get_srvr_end(struct tac_handle *h) 449 { 450 int len; 451 452 len = ntohl(h->response.length); 453 454 if (h->srvr_pos != len) { 455 generr(h, "Invalid length field in response " 456 "from server: end expected at %u, response length %u", 457 h->srvr_pos, len); 458 return -1; 459 } 460 return 0; 461 } 462 463 static int 464 get_str(struct tac_handle *h, const char *field, 465 struct tac_str *ss, size_t len) 466 { 467 if (h->srvr_pos + len > ntohl(h->response.length)) { 468 generr(h, "Invalid length field in %s response from server " 469 "(%lu > %lu)", field, (u_long)(h->srvr_pos + len), 470 (u_long)ntohl(h->response.length)); 471 return -1; 472 } 473 ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL; 474 ss->len = len; 475 h->srvr_pos += len; 476 return 0; 477 } 478 479 static void 480 init_str(struct tac_str *cs) 481 { 482 cs->data = NULL; 483 cs->len = 0; 484 } 485 486 static int 487 read_timed(struct tac_handle *h, void *buf, size_t len, 488 const struct timeval *deadline) 489 { 490 char *ptr; 491 492 ptr = (char *)buf; 493 while (len > 0) { 494 int n; 495 496 n = read(h->fd, ptr, len); 497 if (n == -1) { 498 struct timeval tv; 499 int nfds; 500 501 if (errno != EAGAIN) { 502 generr(h, "Network read error: %s", 503 strerror(errno)); 504 return -1; 505 } 506 507 /* Wait until we can read more data. */ 508 gettimeofday(&tv, NULL); 509 timersub(deadline, &tv, &tv); 510 if (tv.tv_sec >= 0) { 511 fd_set rfds; 512 513 FD_ZERO(&rfds); 514 FD_SET(h->fd, &rfds); 515 nfds = 516 select(h->fd + 1, &rfds, NULL, NULL, &tv); 517 if (nfds == -1) { 518 generr(h, "select: %s", 519 strerror(errno)); 520 return -1; 521 } 522 } else 523 nfds = 0; 524 if (nfds == 0) { 525 generr(h, "Network read timed out"); 526 return -1; 527 } 528 } else if (n == 0) { 529 generr(h, "unexpected EOF from server"); 530 return -1; 531 } else { 532 ptr += n; 533 len -= n; 534 } 535 } 536 return 0; 537 } 538 539 /* 540 * Receive a response from the server and decrypt it. Returns 0 on 541 * success, or -1 on failure. 542 */ 543 static int 544 recv_msg(struct tac_handle *h) 545 { 546 struct timeval deadline; 547 struct tac_msg *msg; 548 u_int32_t len; 549 550 msg = &h->response; 551 gettimeofday(&deadline, NULL); 552 deadline.tv_sec += h->servers[h->cur_server].timeout; 553 554 /* Read the message header and make sure it is reasonable. */ 555 if (read_timed(h, msg, HDRSIZE, &deadline) == -1) 556 return -1; 557 if (memcmp(msg->session_id, h->request.session_id, 558 sizeof msg->session_id) != 0) { 559 generr(h, "Invalid session ID in received message"); 560 return -1; 561 } 562 if (msg->type != h->request.type) { 563 generr(h, "Invalid type in received message" 564 " (got %u, expected %u)", 565 msg->type, h->request.type); 566 return -1; 567 } 568 len = ntohl(msg->length); 569 if (len > BODYSIZE) { 570 generr(h, "Received message too large (%u > %u)", 571 len, BODYSIZE); 572 return -1; 573 } 574 if (msg->seq_no != ++h->last_seq_no) { 575 generr(h, "Invalid sequence number in received message" 576 " (got %u, expected %u)", 577 msg->seq_no, h->last_seq_no); 578 return -1; 579 } 580 581 /* Read the message body. */ 582 if (read_timed(h, msg->u.body, len, &deadline) == -1) 583 return -1; 584 585 /* Decrypt it. */ 586 crypt_msg(h, msg); 587 588 /* 589 * Turn off single-connection mode if the server isn't amenable 590 * to it. 591 */ 592 if (!(msg->flags & TAC_SINGLE_CONNECT)) 593 h->single_connect = 0; 594 return 0; 595 } 596 597 static int 598 save_str(struct tac_handle *h, struct tac_str *cs, const void *data, 599 size_t len) 600 { 601 free_str(cs); 602 if (data != NULL && len != 0) { 603 if ((cs->data = xmalloc(h, len)) == NULL) 604 return -1; 605 cs->len = len; 606 memcpy(cs->data, data, len); 607 } 608 return 0; 609 } 610 611 /* 612 * Send the current request, after encrypting it. Returns 0 on success, 613 * or -1 on failure. 614 */ 615 static int 616 send_msg(struct tac_handle *h) 617 { 618 struct timeval deadline; 619 struct tac_msg *msg; 620 char *ptr; 621 int len; 622 623 if (h->last_seq_no & 1) { 624 generr(h, "Attempt to send message out of sequence"); 625 return -1; 626 } 627 628 if (establish_connection(h) == -1) 629 return -1; 630 631 msg = &h->request; 632 msg->seq_no = ++h->last_seq_no; 633 if (msg->seq_no == 1) 634 gen_session_id(msg); 635 crypt_msg(h, msg); 636 637 if (h->single_connect) 638 msg->flags |= TAC_SINGLE_CONNECT; 639 else 640 msg->flags &= ~TAC_SINGLE_CONNECT; 641 gettimeofday(&deadline, NULL); 642 deadline.tv_sec += h->servers[h->cur_server].timeout; 643 len = HDRSIZE + ntohl(msg->length); 644 ptr = (char *)msg; 645 while (len > 0) { 646 int n; 647 648 n = write(h->fd, ptr, len); 649 if (n == -1) { 650 struct timeval tv; 651 int nfds; 652 653 if (errno != EAGAIN) { 654 generr(h, "Network write error: %s", 655 strerror(errno)); 656 return -1; 657 } 658 659 /* Wait until we can write more data. */ 660 gettimeofday(&tv, NULL); 661 timersub(&deadline, &tv, &tv); 662 if (tv.tv_sec >= 0) { 663 fd_set wfds; 664 665 FD_ZERO(&wfds); 666 FD_SET(h->fd, &wfds); 667 nfds = 668 select(h->fd + 1, NULL, &wfds, NULL, &tv); 669 if (nfds == -1) { 670 generr(h, "select: %s", 671 strerror(errno)); 672 return -1; 673 } 674 } else 675 nfds = 0; 676 if (nfds == 0) { 677 generr(h, "Network write timed out"); 678 return -1; 679 } 680 } else { 681 ptr += n; 682 len -= n; 683 } 684 } 685 return 0; 686 } 687 688 static int 689 tac_add_server_av(struct tac_handle *h, const char *host, int port, 690 const char *secret, int timeout, int flags, const char *const *avs) 691 { 692 struct tac_server *srvp; 693 const char *p; 694 size_t len; 695 int i; 696 697 if (h->num_servers >= MAXSERVERS) { 698 generr(h, "Too many TACACS+ servers specified"); 699 return -1; 700 } 701 srvp = &h->servers[h->num_servers]; 702 703 memset(&srvp->addr, 0, sizeof srvp->addr); 704 srvp->addr.sin_len = sizeof srvp->addr; 705 srvp->addr.sin_family = AF_INET; 706 if (!inet_aton(host, &srvp->addr.sin_addr)) { 707 struct hostent *hent; 708 709 if ((hent = gethostbyname(host)) == NULL) { 710 generr(h, "%s: host not found", host); 711 return -1; 712 } 713 memcpy(&srvp->addr.sin_addr, hent->h_addr, 714 sizeof srvp->addr.sin_addr); 715 } 716 srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT); 717 if ((srvp->secret = xstrdup(h, secret)) == NULL) 718 return -1; 719 srvp->timeout = timeout; 720 srvp->flags = flags; 721 srvp->navs = 0; 722 for (i = 0; avs[i] != NULL; i++) { 723 if (i >= MAXAVPAIRS) { 724 generr(h, "too many AV pairs"); 725 goto fail; 726 } 727 for (p = avs[i], len = 0; is_arg(*p); p++) 728 len++; 729 if (p == avs[i] || *p != '=') { 730 generr(h, "invalid AV pair %d", i); 731 goto fail; 732 } 733 while (*p++ != '\0') 734 len++; 735 if ((srvp->avs[i].data = xstrdup(h, avs[i])) == NULL) 736 goto fail; 737 srvp->avs[i].len = len; 738 srvp->navs++; 739 } 740 h->num_servers++; 741 return 0; 742 fail: 743 memset_s(srvp->secret, strlen(srvp->secret), 0, strlen(srvp->secret)); 744 free(srvp->secret); 745 srvp->secret = NULL; 746 for (i = 0; i < srvp->navs; i++) { 747 free(srvp->avs[i].data); 748 srvp->avs[i].data = NULL; 749 srvp->avs[i].len = 0; 750 } 751 return -1; 752 } 753 754 int 755 tac_add_server(struct tac_handle *h, const char *host, int port, 756 const char *secret, int timeout, int flags) 757 { 758 const char *const *avs = { NULL }; 759 760 return tac_add_server_av(h, host, port, secret, timeout, flags, avs); 761 } 762 763 void 764 tac_close(struct tac_handle *h) 765 { 766 int i, srv; 767 768 if (h->fd != -1) 769 close(h->fd); 770 for (srv = 0; srv < h->num_servers; srv++) { 771 memset(h->servers[srv].secret, 0, 772 strlen(h->servers[srv].secret)); 773 free(h->servers[srv].secret); 774 } 775 free_str(&h->user); 776 free_str(&h->port); 777 free_str(&h->rem_addr); 778 free_str(&h->data); 779 free_str(&h->user_msg); 780 for (i=0; i<MAXAVPAIRS; i++) 781 free_str(&(h->avs[i])); 782 783 /* Clear everything else before freeing memory */ 784 memset(h, 0, sizeof(struct tac_handle)); 785 free(h); 786 } 787 788 static void 789 freev(char **fields, int nfields) 790 { 791 if (fields != NULL) { 792 while (nfields-- > 0) 793 free(fields[nfields]); 794 free(fields); 795 } 796 } 797 798 int 799 tac_config(struct tac_handle *h, const char *path) 800 { 801 FILE *fp; 802 char **fields; 803 int linenum, nfields; 804 int retval; 805 806 if (path == NULL) 807 path = PATH_TACPLUS_CONF; 808 if ((fp = fopen(path, "r")) == NULL) { 809 generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); 810 return -1; 811 } 812 retval = 0; 813 linenum = nfields = 0; 814 fields = NULL; 815 while ((fields = openpam_readlinev(fp, &linenum, &nfields)) != NULL) { 816 char *host, *res; 817 char *port_str; 818 char *secret; 819 char *timeout_str; 820 char *end; 821 unsigned long timeout; 822 int port; 823 int options; 824 int i; 825 826 if (nfields == 0) { 827 freev(fields, nfields); 828 continue; 829 } 830 if (nfields < 2) { 831 generr(h, "%s:%d: missing shared secret", path, 832 linenum); 833 retval = -1; 834 break; 835 } 836 host = fields[0]; 837 secret = fields[1]; 838 839 /* Parse and validate the fields. */ 840 res = host; 841 host = strsep(&res, ":"); 842 port_str = strsep(&res, ":"); 843 if (port_str != NULL) { 844 port = strtoul(port_str, &end, 10); 845 if (port_str[0] == '\0' || *end != '\0') { 846 generr(h, "%s:%d: invalid port", path, 847 linenum); 848 retval = -1; 849 break; 850 } 851 } else 852 port = 0; 853 i = 2; 854 if (nfields > i && strlen(fields[i]) > 0 && 855 strspn(fields[i], "0123456789") == strlen(fields[i])) { 856 timeout_str = fields[i]; 857 timeout = strtoul(timeout_str, &end, 10); 858 if (timeout_str[0] == '\0' || *end != '\0') { 859 generr(h, "%s:%d: invalid timeout", path, 860 linenum); 861 retval = -1; 862 break; 863 } 864 i++; 865 } else 866 timeout = TIMEOUT; 867 options = 0; 868 if (nfields > i && 869 strcmp(fields[i], "single-connection") == 0) { 870 options |= TAC_SRVR_SINGLE_CONNECT; 871 i++; 872 } 873 if (tac_add_server_av(h, host, port, secret, timeout, 874 options, (const char *const *)(fields + i)) == -1) { 875 char msg[ERRSIZE]; 876 877 strcpy(msg, h->errmsg); 878 generr(h, "%s:%d: %s", path, linenum, msg); 879 retval = -1; 880 break; 881 } 882 memset_s(secret, strlen(secret), 0, strlen(secret)); 883 freev(fields, nfields); 884 } 885 freev(fields, nfields); 886 fclose(fp); 887 return retval; 888 } 889 890 int 891 tac_create_authen(struct tac_handle *h, int action, int type, int service) 892 { 893 struct tac_authen_start *as; 894 895 create_msg(h, TAC_AUTHEN, action, type); 896 897 as = &h->request.u.authen_start; 898 as->action = action; 899 as->priv_lvl = TAC_PRIV_LVL_USER; 900 as->authen_type = type; 901 as->service = service; 902 903 return 0; 904 } 905 906 int 907 tac_create_author(struct tac_handle *h, int method, int type, int service) 908 { 909 struct tac_author_request *areq; 910 911 create_msg(h, TAC_AUTHOR, method, type); 912 913 areq = &h->request.u.author_request; 914 areq->authen_meth = method; 915 areq->priv_lvl = TAC_PRIV_LVL_USER; 916 areq->authen_type = type; 917 areq->service = service; 918 919 return 0; 920 } 921 922 int 923 tac_create_acct(struct tac_handle *h, int acct, int action, int type, int service) 924 { 925 struct tac_acct_start *as; 926 927 create_msg(h, TAC_ACCT, action, type); 928 929 as = &h->request.u.acct_start; 930 as->action = acct; 931 as->authen_action = action; 932 as->priv_lvl = TAC_PRIV_LVL_USER; 933 as->authen_type = type; 934 as->authen_service = service; 935 936 return 0; 937 } 938 939 static void 940 create_msg(struct tac_handle *h, int msg_type, int var, int type) 941 { 942 struct tac_msg *msg; 943 int i; 944 945 h->last_seq_no = 0; 946 947 msg = &h->request; 948 msg->type = msg_type; 949 msg->version = protocol_version(msg_type, var, type); 950 msg->flags = 0; /* encrypted packet body */ 951 952 free_str(&h->user); 953 free_str(&h->port); 954 free_str(&h->rem_addr); 955 free_str(&h->data); 956 free_str(&h->user_msg); 957 958 for (i=0; i<MAXAVPAIRS; i++) 959 free_str(&(h->avs[i])); 960 } 961 962 void * 963 tac_get_data(struct tac_handle *h, size_t *len) 964 { 965 return dup_str(h, &h->srvr_data, len); 966 } 967 968 char * 969 tac_get_msg(struct tac_handle *h) 970 { 971 return dup_str(h, &h->srvr_msg, NULL); 972 } 973 974 /* 975 * Create and initialize a tac_handle structure, and return it to the 976 * caller. Can fail only if the necessary memory cannot be allocated. 977 * In that case, it returns NULL. 978 */ 979 struct tac_handle * 980 tac_open(void) 981 { 982 int i; 983 struct tac_handle *h; 984 985 h = (struct tac_handle *)malloc(sizeof(struct tac_handle)); 986 if (h != NULL) { 987 h->fd = -1; 988 h->num_servers = 0; 989 h->cur_server = 0; 990 h->errmsg[0] = '\0'; 991 init_str(&h->user); 992 init_str(&h->port); 993 init_str(&h->rem_addr); 994 init_str(&h->data); 995 init_str(&h->user_msg); 996 for (i=0; i<MAXAVPAIRS; i++) { 997 init_str(&(h->avs[i])); 998 init_str(&(h->srvr_avs[i])); 999 } 1000 init_str(&h->srvr_msg); 1001 init_str(&h->srvr_data); 1002 } 1003 return h; 1004 } 1005 1006 int 1007 tac_send_authen(struct tac_handle *h) 1008 { 1009 struct tac_authen_reply *ar; 1010 1011 if (h->num_servers == 0) 1012 return -1; 1013 1014 if (h->last_seq_no == 0) { /* Authentication START packet */ 1015 struct tac_authen_start *as; 1016 1017 as = &h->request.u.authen_start; 1018 h->request.length = 1019 htonl(offsetof(struct tac_authen_start, rest[0])); 1020 if (add_str_8(h, &as->user_len, &h->user) == -1 || 1021 add_str_8(h, &as->port_len, &h->port) == -1 || 1022 add_str_8(h, &as->rem_addr_len, &h->rem_addr) == -1 || 1023 add_str_8(h, &as->data_len, &h->data) == -1) 1024 return -1; 1025 } else { /* Authentication CONTINUE packet */ 1026 struct tac_authen_cont *ac; 1027 1028 ac = &h->request.u.authen_cont; 1029 ac->flags = 0; 1030 h->request.length = 1031 htonl(offsetof(struct tac_authen_cont, rest[0])); 1032 if (add_str_16(h, &ac->user_msg_len, &h->user_msg) == -1 || 1033 add_str_16(h, &ac->data_len, &h->data) == -1) 1034 return -1; 1035 } 1036 1037 /* Send the message and retrieve the reply. */ 1038 if (send_msg(h) == -1 || recv_msg(h) == -1) 1039 return -1; 1040 1041 /* Scan the optional fields in the reply. */ 1042 ar = &h->response.u.authen_reply; 1043 h->srvr_pos = offsetof(struct tac_authen_reply, rest[0]); 1044 if (get_str(h, "msg", &h->srvr_msg, ntohs(ar->msg_len)) == -1 || 1045 get_str(h, "data", &h->srvr_data, ntohs(ar->data_len)) == -1 || 1046 get_srvr_end(h) == -1) 1047 return -1; 1048 1049 if (!h->single_connect && 1050 ar->status != TAC_AUTHEN_STATUS_GETDATA && 1051 ar->status != TAC_AUTHEN_STATUS_GETUSER && 1052 ar->status != TAC_AUTHEN_STATUS_GETPASS) 1053 close_connection(h); 1054 1055 return ar->flags << 8 | ar->status; 1056 } 1057 1058 int 1059 tac_send_author(struct tac_handle *h) 1060 { 1061 int i, current; 1062 char dbgstr[64]; 1063 struct tac_author_request *areq = &h->request.u.author_request; 1064 struct tac_author_response *ares = &h->response.u.author_response; 1065 struct tac_server *srvp; 1066 1067 h->request.length = 1068 htonl(offsetof(struct tac_author_request, rest[0])); 1069 1070 /* Count each specified AV pair */ 1071 for (areq->av_cnt=0, i=0; i<MAXAVPAIRS; i++) 1072 if (h->avs[i].len && h->avs[i].data) 1073 areq->av_cnt++; 1074 1075 /* 1076 * Each AV size is a byte starting right after 'av_cnt'. Update the 1077 * offset to include these AV sizes. 1078 */ 1079 h->request.length = ntohl(htonl(h->request.length) + areq->av_cnt); 1080 1081 /* Now add the string arguments from 'h' */ 1082 if (add_str_8(h, &areq->user_len, &h->user) == -1 || 1083 add_str_8(h, &areq->port_len, &h->port) == -1 || 1084 add_str_8(h, &areq->rem_addr_len, &h->rem_addr) == -1) 1085 return -1; 1086 1087 /* Add each AV pair, the size of each placed in areq->rest[current] */ 1088 for (current=0, i=0; i<MAXAVPAIRS; i++) { 1089 if (h->avs[i].len && h->avs[i].data) { 1090 if (add_str_8(h, &areq->rest[current++], 1091 &(h->avs[i])) == -1) 1092 return -1; 1093 } 1094 } 1095 1096 /* Send the message and retrieve the reply. */ 1097 if (send_msg(h) == -1 || recv_msg(h) == -1) 1098 return -1; 1099 srvp = &h->servers[h->cur_server]; 1100 1101 /* Update the offset in the response packet based on av pairs count */ 1102 h->srvr_pos = offsetof(struct tac_author_response, rest[0]) + 1103 ares->av_cnt; 1104 1105 /* Scan the optional fields in the response. */ 1106 if (get_str(h, "msg", &h->srvr_msg, ntohs(ares->msg_len)) == -1 || 1107 get_str(h, "data", &h->srvr_data, ntohs(ares->data_len)) ==-1) 1108 return -1; 1109 1110 /* Get each AV pair (just setting pointers, not malloc'ing) */ 1111 clear_srvr_avs(h); 1112 for (i=0; i<ares->av_cnt; i++) { 1113 snprintf(dbgstr, sizeof dbgstr, "av-pair-%d", i); 1114 if (get_str(h, dbgstr, &(h->srvr_avs[i]), 1115 ares->rest[i]) == -1) 1116 return -1; 1117 h->srvr_navs++; 1118 } 1119 1120 /* Should have ended up at the end */ 1121 if (get_srvr_end(h) == -1) 1122 return -1; 1123 1124 /* Sanity checks */ 1125 if (!h->single_connect) 1126 close_connection(h); 1127 1128 return (h->srvr_navs + srvp->navs) << 8 | ares->status; 1129 } 1130 1131 int 1132 tac_send_acct(struct tac_handle *h) 1133 { 1134 register int i, current; 1135 struct tac_acct_start *as = &h->request.u.acct_start; 1136 struct tac_acct_reply *ar = &h->response.u.acct_reply; 1137 1138 /* start */ 1139 as = &h->request.u.acct_start; 1140 h->request.length = htonl(offsetof(struct tac_acct_start, rest[0])); 1141 for (as->av_cnt = 0, i = 0; i < MAXAVPAIRS; i++) 1142 if (h->avs[i].len && h->avs[i].data) 1143 as->av_cnt++; 1144 h->request.length = ntohl(htonl(h->request.length) + as->av_cnt); 1145 1146 if (add_str_8(h, &as->user_len, &h->user) == -1 || 1147 add_str_8(h, &as->port_len, &h->port) == -1 || 1148 add_str_8(h, &as->rem_addr_len, &h->rem_addr) == -1) 1149 return -1; 1150 1151 for (i = current = 0; i < MAXAVPAIRS; i++) 1152 if (h->avs[i].len && h->avs[i].data) 1153 if (add_str_8(h, &as->rest[current++], &(h->avs[i])) == -1) 1154 return -1; 1155 1156 /* send */ 1157 if (send_msg(h) == -1 || recv_msg(h) == -1) 1158 return -1; 1159 1160 /* reply */ 1161 h->srvr_pos = offsetof(struct tac_acct_reply, rest[0]); 1162 if (get_str(h, "msg", &h->srvr_msg, ntohs(ar->msg_len)) == -1 || 1163 get_str(h, "data", &h->srvr_data, ntohs(ar->data_len)) == -1 || 1164 get_srvr_end(h) == -1) 1165 return -1; 1166 1167 /* Sanity checks */ 1168 if (!h->single_connect) 1169 close_connection(h); 1170 1171 return ar->status; 1172 } 1173 1174 int 1175 tac_set_rem_addr(struct tac_handle *h, const char *addr) 1176 { 1177 return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0); 1178 } 1179 1180 int 1181 tac_set_data(struct tac_handle *h, const void *data, size_t data_len) 1182 { 1183 return save_str(h, &h->data, data, data_len); 1184 } 1185 1186 int 1187 tac_set_msg(struct tac_handle *h, const char *msg) 1188 { 1189 return save_str(h, &h->user_msg, msg, msg != NULL ? strlen(msg) : 0); 1190 } 1191 1192 int 1193 tac_set_port(struct tac_handle *h, const char *port) 1194 { 1195 return save_str(h, &h->port, port, port != NULL ? strlen(port) : 0); 1196 } 1197 1198 int 1199 tac_set_priv(struct tac_handle *h, int priv) 1200 { 1201 if (!(TAC_PRIV_LVL_MIN <= priv && priv <= TAC_PRIV_LVL_MAX)) { 1202 generr(h, "Attempt to set invalid privilege level"); 1203 return -1; 1204 } 1205 h->request.u.authen_start.priv_lvl = priv; 1206 return 0; 1207 } 1208 1209 int 1210 tac_set_user(struct tac_handle *h, const char *user) 1211 { 1212 return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0); 1213 } 1214 1215 int 1216 tac_set_av(struct tac_handle *h, u_int index, const char *av) 1217 { 1218 if (index >= MAXAVPAIRS) 1219 return -1; 1220 return save_str(h, &(h->avs[index]), av, av != NULL ? strlen(av) : 0); 1221 } 1222 1223 char * 1224 tac_get_av(struct tac_handle *h, u_int index) 1225 { 1226 struct tac_server *srvp; 1227 1228 if (index < h->srvr_navs) 1229 return dup_str(h, &h->srvr_avs[index], NULL); 1230 index -= h->srvr_navs; 1231 srvp = &h->servers[h->cur_server]; 1232 if (index < srvp->navs) 1233 return xstrdup(h, srvp->avs[index].data); 1234 return NULL; 1235 } 1236 1237 char * 1238 tac_get_av_value(struct tac_handle *h, const char *attribute) 1239 { 1240 int i, attr_len; 1241 int found_seperator; 1242 char *ch, *end; 1243 struct tac_str *candidate; 1244 struct tac_str value; 1245 struct tac_server *srvp = &h->servers[h->cur_server]; 1246 1247 if (attribute == NULL || (attr_len = strlen(attribute)) == 0) 1248 return NULL; 1249 1250 for (i = 0; i < h->srvr_navs + srvp->navs; i++) { 1251 if (i < h->srvr_navs) 1252 candidate = &h->srvr_avs[i]; 1253 else 1254 candidate = &srvp->avs[i - h->srvr_navs]; 1255 1256 if (attr_len < candidate->len && 1257 strncmp(candidate->data, attribute, attr_len) == 0) { 1258 1259 ch = candidate->data + attr_len; 1260 end = candidate->data + candidate->len; 1261 1262 /* 1263 * Sift out the white space between A and V (should not 1264 * be any, but don't trust implementation of server...) 1265 */ 1266 found_seperator = 0; 1267 while ((*ch == '=' || *ch == '*' || *ch == ' ' || 1268 *ch == '\t') && ch != end) { 1269 if (*ch == '=' || *ch == '*') 1270 found_seperator++; 1271 ch++; 1272 } 1273 1274 /* 1275 * Note: 1276 * The case of 'attribute' == "foo" and 1277 * h->srvr_avs[0] = "foobie=var1" 1278 * h->srvr_avs[1] = "foo=var2" 1279 * is handled. 1280 * 1281 * Note that for empty string attribute values a 1282 * 0-length string is returned in order to distinguish 1283 * against unset values. 1284 * dup_str() will handle srvr.len == 0 correctly. 1285 */ 1286 if (found_seperator == 1) { 1287 value.len = end - ch; 1288 value.data = ch; 1289 return dup_str(h, &value, NULL); 1290 } 1291 } 1292 } 1293 return NULL; 1294 } 1295 1296 void 1297 tac_clear_avs(struct tac_handle *h) 1298 { 1299 int i; 1300 for (i=0; i<MAXAVPAIRS; i++) 1301 save_str(h, &(h->avs[i]), NULL, 0); 1302 } 1303 1304 static void 1305 clear_srvr_avs(struct tac_handle *h) 1306 { 1307 int i; 1308 1309 for (i = 0; i < h->srvr_navs; i++) 1310 init_str(&(h->srvr_avs[i])); 1311 h->srvr_navs = 0; 1312 } 1313 1314 1315 const char * 1316 tac_strerror(struct tac_handle *h) 1317 { 1318 return h->errmsg; 1319 } 1320 1321 static void * 1322 xmalloc(struct tac_handle *h, size_t size) 1323 { 1324 void *r; 1325 1326 if ((r = malloc(size)) == NULL) 1327 generr(h, "Out of memory"); 1328 return r; 1329 } 1330 1331 static char * 1332 xstrdup(struct tac_handle *h, const char *s) 1333 { 1334 char *r; 1335 1336 if ((r = strdup(s)) == NULL) 1337 generr(h, "Out of memory"); 1338 return r; 1339 } 1340