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