1 /*- 2 * Copyright 1998 Juniper Networks, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <sys/time.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 35 #include <assert.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <md5.h> 39 #include <netdb.h> 40 #include <stdarg.h> 41 #include <stddef.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "taclib_private.h" 48 49 static int add_str_8(struct tac_handle *, u_int8_t *, 50 struct clnt_str *); 51 static int add_str_16(struct tac_handle *, u_int16_t *, 52 struct clnt_str *); 53 static int authen_version(int, int); 54 static void close_connection(struct tac_handle *); 55 static int conn_server(struct tac_handle *); 56 static void crypt_msg(struct tac_handle *, struct tac_msg *); 57 static void *dup_str(struct tac_handle *, const struct srvr_str *, 58 size_t *); 59 static int establish_connection(struct tac_handle *); 60 static void free_str(struct clnt_str *); 61 static void generr(struct tac_handle *, const char *, ...) 62 __printflike(2, 3); 63 static void gen_session_id(struct tac_msg *); 64 static int get_srvr_end(struct tac_handle *); 65 static int get_srvr_str(struct tac_handle *, struct srvr_str *, 66 size_t); 67 static void init_clnt_str(struct clnt_str *); 68 static void init_srvr_str(struct srvr_str *); 69 static int read_timed(struct tac_handle *, void *, size_t, 70 const struct timeval *); 71 static int recv_msg(struct tac_handle *); 72 static int save_str(struct tac_handle *, struct clnt_str *, 73 const void *, size_t); 74 static int send_msg(struct tac_handle *); 75 static int split(char *, char *[], int, char *, size_t); 76 static void *xmalloc(struct tac_handle *, size_t); 77 static char *xstrdup(struct tac_handle *, const char *); 78 79 /* 80 * Append some optional data to the current request, and store its 81 * length into the 8-bit field referenced by "fld". Returns 0 on 82 * success, or -1 on failure. 83 * 84 * This function also frees the "cs" string data and initializes it 85 * for the next time. 86 */ 87 static int 88 add_str_8(struct tac_handle *h, u_int8_t *fld, struct clnt_str *cs) 89 { 90 u_int16_t len; 91 92 if (add_str_16(h, &len, cs) == -1) 93 return -1; 94 len = ntohs(len); 95 if (len > 0xff) { 96 generr(h, "Field too long"); 97 return -1; 98 } 99 *fld = len; 100 return 0; 101 } 102 103 /* 104 * Append some optional data to the current request, and store its 105 * length into the 16-bit field (network byte order) referenced by 106 * "fld". Returns 0 on success, or -1 on failure. 107 * 108 * This function also frees the "cs" string data and initializes it 109 * for the next time. 110 */ 111 static int 112 add_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs) 113 { 114 size_t len; 115 116 len = cs->len; 117 if (cs->data == NULL) 118 len = 0; 119 if (len != 0) { 120 int offset; 121 122 if (len > 0xffff) { 123 generr(h, "Field too long"); 124 return -1; 125 } 126 offset = ntohl(h->request.length); 127 if (offset + len > BODYSIZE) { 128 generr(h, "Message too long"); 129 return -1; 130 } 131 memcpy(h->request.u.body + offset, cs->data, len); 132 h->request.length = htonl(offset + len); 133 } 134 *fld = htons(len); 135 free_str(cs); 136 return 0; 137 } 138 139 static int 140 authen_version(int action, int type) 141 { 142 int minor; 143 144 switch (action) { 145 146 case TAC_AUTHEN_LOGIN: 147 switch (type) { 148 149 case TAC_AUTHEN_TYPE_PAP: 150 case TAC_AUTHEN_TYPE_CHAP: 151 case TAC_AUTHEN_TYPE_MSCHAP: 152 case TAC_AUTHEN_TYPE_ARAP: 153 minor = 1; 154 break; 155 156 default: 157 minor = 0; 158 break; 159 } 160 break; 161 162 case TAC_AUTHEN_SENDAUTH: 163 minor = 1; 164 break; 165 166 default: 167 minor = 0; 168 break; 169 }; 170 171 return TAC_VER_MAJOR << 4 | minor; 172 } 173 174 static void 175 close_connection(struct tac_handle *h) 176 { 177 if (h->fd != -1) { 178 close(h->fd); 179 h->fd = -1; 180 } 181 } 182 183 static int 184 conn_server(struct tac_handle *h) 185 { 186 const struct tac_server *srvp = &h->servers[h->cur_server]; 187 int flags; 188 189 if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { 190 generr(h, "Cannot create socket: %s", strerror(errno)); 191 return -1; 192 } 193 if ((flags = fcntl(h->fd, F_GETFL, 0)) == -1 || 194 fcntl(h->fd, F_SETFL, flags | O_NONBLOCK) == -1) { 195 generr(h, "Cannot set non-blocking mode on socket: %s", 196 strerror(errno)); 197 close(h->fd); 198 h->fd = -1; 199 return -1; 200 } 201 if (connect(h->fd, (struct sockaddr *)&srvp->addr, 202 sizeof srvp->addr) == 0) 203 return 0; 204 205 if (errno == EINPROGRESS) { 206 fd_set wfds; 207 struct timeval tv; 208 int nfds; 209 struct sockaddr peer; 210 int peerlen; 211 int err; 212 int errlen; 213 214 /* Wait for the connection to complete. */ 215 FD_ZERO(&wfds); 216 FD_SET(h->fd, &wfds); 217 tv.tv_sec = srvp->timeout; 218 tv.tv_usec = 0; 219 nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv); 220 if (nfds == -1) { 221 generr(h, "select: %s", strerror(errno)); 222 close(h->fd); 223 h->fd = -1; 224 return -1; 225 } 226 if (nfds == 0) { 227 generr(h, "connect: timed out"); 228 close(h->fd); 229 h->fd = -1; 230 return -1; 231 } 232 233 /* See whether we are connected now. */ 234 peerlen = sizeof peer; 235 if (getpeername(h->fd, &peer, &peerlen) == 0) 236 return 0; 237 238 if (errno != ENOTCONN) { 239 generr(h, "getpeername: %s", strerror(errno)); 240 close(h->fd); 241 h->fd = -1; 242 return -1; 243 } 244 245 /* Find out why the connect failed. */ 246 errlen = sizeof err; 247 getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen); 248 errno = err; 249 } 250 generr(h, "connect: %s", strerror(errno)); 251 close(h->fd); 252 h->fd = -1; 253 return -1; 254 } 255 256 /* 257 * Encrypt or decrypt a message. The operations are symmetrical. 258 */ 259 static void 260 crypt_msg(struct tac_handle *h, struct tac_msg *msg) 261 { 262 const char *secret; 263 MD5_CTX base_ctx; 264 MD5_CTX ctx; 265 unsigned char md5[16]; 266 int chunk; 267 int msg_len; 268 269 secret = h->servers[h->cur_server].secret; 270 if (secret[0] == '\0') 271 msg->flags |= TAC_UNENCRYPTED; 272 if (msg->flags & TAC_UNENCRYPTED) 273 return; 274 275 msg_len = ntohl(msg->length); 276 277 MD5Init(&base_ctx); 278 MD5Update(&base_ctx, msg->session_id, sizeof msg->session_id); 279 MD5Update(&base_ctx, secret, strlen(secret)); 280 MD5Update(&base_ctx, &msg->version, sizeof msg->version); 281 MD5Update(&base_ctx, &msg->seq_no, sizeof msg->seq_no); 282 283 ctx = base_ctx; 284 for (chunk = 0; chunk < msg_len; chunk += sizeof md5) { 285 int chunk_len; 286 int i; 287 288 MD5Final(md5, &ctx); 289 290 if ((chunk_len = msg_len - chunk) > sizeof md5) 291 chunk_len = sizeof md5; 292 for (i = 0; i < chunk_len; i++) 293 msg->u.body[chunk + i] ^= md5[i]; 294 295 ctx = base_ctx; 296 MD5Update(&ctx, md5, sizeof md5); 297 } 298 } 299 300 /* 301 * Return a dynamically allocated copy of the given server string. 302 * The copy is null-terminated. If "len" is non-NULL, the length of 303 * the string (excluding the terminating null byte) is stored via it. 304 * Returns NULL on failure. Empty strings are still allocated even 305 * though they have no content. 306 */ 307 static void * 308 dup_str(struct tac_handle *h, const struct srvr_str *ss, size_t *len) 309 { 310 unsigned char *p; 311 312 if ((p = (unsigned char *)xmalloc(h, ss->len + 1)) == NULL) 313 return NULL; 314 if (ss->data != NULL && ss->len != 0) 315 memcpy(p, ss->data, ss->len); 316 p[ss->len] = '\0'; 317 if (len != NULL) 318 *len = ss->len; 319 return p; 320 } 321 322 static int 323 establish_connection(struct tac_handle *h) 324 { 325 int i; 326 327 if (h->fd >= 0) /* Already connected. */ 328 return 0; 329 if (h->num_servers == 0) { 330 generr(h, "No TACACS+ servers specified"); 331 return -1; 332 } 333 /* 334 * Try the servers round-robin. We begin with the one that 335 * worked for us the last time. That way, once we find a good 336 * server, we won't waste any more time trying the bad ones. 337 */ 338 for (i = 0; i < h->num_servers; i++) { 339 if (conn_server(h) == 0) { 340 h->single_connect = (h->servers[h->cur_server].flags & 341 TAC_SRVR_SINGLE_CONNECT) != 0; 342 return 0; 343 } 344 if (++h->cur_server >= h->num_servers) /* Wrap around */ 345 h->cur_server = 0; 346 } 347 /* Just return whatever error was last reported by conn_server(). */ 348 return -1; 349 } 350 351 /* 352 * Free a client string, obliterating its contents first for security. 353 */ 354 static void 355 free_str(struct clnt_str *cs) 356 { 357 if (cs->data != NULL) { 358 memset(cs->data, 0, cs->len); 359 free(cs->data); 360 cs->data = NULL; 361 cs->len = 0; 362 } 363 } 364 365 static void 366 generr(struct tac_handle *h, const char *format, ...) 367 { 368 va_list ap; 369 370 va_start(ap, format); 371 vsnprintf(h->errmsg, ERRSIZE, format, ap); 372 va_end(ap); 373 } 374 375 static void 376 gen_session_id(struct tac_msg *msg) 377 { 378 int r; 379 380 r = random(); 381 msg->session_id[0] = r >> 8; 382 msg->session_id[1] = r; 383 r = random(); 384 msg->session_id[2] = r >> 8; 385 msg->session_id[3] = r; 386 } 387 388 /* 389 * Verify that we are exactly at the end of the response message. 390 * Returns 0 on success, -1 on failure. 391 */ 392 static int 393 get_srvr_end(struct tac_handle *h) 394 { 395 if (h->srvr_pos != ntohl(h->response.length)) { 396 generr(h, "Invalid length field in response from server"); 397 return -1; 398 } 399 return 0; 400 } 401 402 static int 403 get_srvr_str(struct tac_handle *h, struct srvr_str *ss, size_t len) 404 { 405 if (h->srvr_pos + len > ntohl(h->response.length)) { 406 generr(h, "Invalid length field in response from server"); 407 return -1; 408 } 409 ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL; 410 ss->len = len; 411 h->srvr_pos += len; 412 return 0; 413 } 414 415 static void 416 init_clnt_str(struct clnt_str *cs) 417 { 418 cs->data = NULL; 419 cs->len = 0; 420 } 421 422 static void 423 init_srvr_str(struct srvr_str *ss) 424 { 425 ss->data = NULL; 426 ss->len = 0; 427 } 428 429 static int 430 read_timed(struct tac_handle *h, void *buf, size_t len, 431 const struct timeval *deadline) 432 { 433 char *ptr; 434 435 ptr = (char *)buf; 436 while (len > 0) { 437 int n; 438 439 n = read(h->fd, ptr, len); 440 if (n == -1) { 441 struct timeval tv; 442 int nfds; 443 444 if (errno != EAGAIN) { 445 generr(h, "Network read error: %s", 446 strerror(errno)); 447 return -1; 448 } 449 450 /* Wait until we can read more data. */ 451 gettimeofday(&tv, NULL); 452 timersub(deadline, &tv, &tv); 453 if (tv.tv_sec >= 0) { 454 fd_set rfds; 455 456 FD_ZERO(&rfds); 457 FD_SET(h->fd, &rfds); 458 nfds = 459 select(h->fd + 1, &rfds, NULL, NULL, &tv); 460 if (nfds == -1) { 461 generr(h, "select: %s", 462 strerror(errno)); 463 return -1; 464 } 465 } else 466 nfds = 0; 467 if (nfds == 0) { 468 generr(h, "Network read timed out"); 469 return -1; 470 } 471 } else if (n == 0) { 472 generr(h, "unexpected EOF from server"); 473 return -1; 474 } else { 475 ptr += n; 476 len -= n; 477 } 478 } 479 return 0; 480 } 481 482 /* 483 * Receive a response from the server and decrypt it. Returns 0 on 484 * success, or -1 on failure. 485 */ 486 static int 487 recv_msg(struct tac_handle *h) 488 { 489 struct timeval deadline; 490 struct tac_msg *msg; 491 size_t len; 492 493 msg = &h->response; 494 gettimeofday(&deadline, NULL); 495 deadline.tv_sec += h->servers[h->cur_server].timeout; 496 497 /* Read the message header and make sure it is reasonable. */ 498 if (read_timed(h, msg, HDRSIZE, &deadline) == -1) 499 return -1; 500 if (memcmp(msg->session_id, h->request.session_id, 501 sizeof msg->session_id) != 0) { 502 generr(h, "Invalid session ID in received message"); 503 return -1; 504 } 505 if (msg->type != h->request.type) { 506 generr(h, "Invalid type in received message"); 507 return -1; 508 } 509 len = ntohl(msg->length); 510 if (len > BODYSIZE) { 511 generr(h, "Received message too large"); 512 return -1; 513 } 514 if (msg->seq_no != ++h->last_seq_no) { 515 generr(h, "Invalid sequence number in received message"); 516 return -1; 517 } 518 519 /* Read the message body. */ 520 if (read_timed(h, msg->u.body, len, &deadline) == -1) 521 return -1; 522 523 /* Decrypt it. */ 524 crypt_msg(h, msg); 525 526 /* 527 * Turn off single-connection mode if the server isn't amenable 528 * to it. 529 */ 530 if (!(msg->flags & TAC_SINGLE_CONNECT)) 531 h->single_connect = 0; 532 return 0; 533 } 534 535 static int 536 save_str(struct tac_handle *h, struct clnt_str *cs, const void *data, 537 size_t len) 538 { 539 free_str(cs); 540 if (data != NULL && len != 0) { 541 if ((cs->data = xmalloc(h, len)) == NULL) 542 return -1; 543 cs->len = len; 544 memcpy(cs->data, data, len); 545 } 546 return 0; 547 } 548 549 /* 550 * Send the current request, after encrypting it. Returns 0 on success, 551 * or -1 on failure. 552 */ 553 static int 554 send_msg(struct tac_handle *h) 555 { 556 struct timeval deadline; 557 struct tac_msg *msg; 558 char *ptr; 559 int len; 560 561 if (h->last_seq_no & 1) { 562 generr(h, "Attempt to send message out of sequence"); 563 return -1; 564 } 565 566 msg = &h->request; 567 msg->seq_no = ++h->last_seq_no; 568 if (msg->seq_no == 1) 569 gen_session_id(msg); 570 crypt_msg(h, msg); 571 572 if (establish_connection(h) == -1) 573 return -1; 574 575 if (h->single_connect) 576 msg->flags |= TAC_SINGLE_CONNECT; 577 else 578 msg->flags &= ~TAC_SINGLE_CONNECT; 579 gettimeofday(&deadline, NULL); 580 deadline.tv_sec += h->servers[h->cur_server].timeout; 581 len = HDRSIZE + ntohl(msg->length); 582 ptr = (char *)msg; 583 while (len > 0) { 584 int n; 585 586 n = write(h->fd, ptr, len); 587 if (n == -1) { 588 struct timeval tv; 589 int nfds; 590 591 if (errno != EAGAIN) { 592 generr(h, "Network write error: %s", 593 strerror(errno)); 594 return -1; 595 } 596 597 /* Wait until we can write more data. */ 598 gettimeofday(&tv, NULL); 599 timersub(&deadline, &tv, &tv); 600 if (tv.tv_sec >= 0) { 601 fd_set wfds; 602 603 FD_ZERO(&wfds); 604 FD_SET(h->fd, &wfds); 605 nfds = 606 select(h->fd + 1, NULL, &wfds, NULL, &tv); 607 if (nfds == -1) { 608 generr(h, "select: %s", 609 strerror(errno)); 610 return -1; 611 } 612 } else 613 nfds = 0; 614 if (nfds == 0) { 615 generr(h, "Network write timed out"); 616 return -1; 617 } 618 } else { 619 ptr += n; 620 len -= n; 621 } 622 } 623 return 0; 624 } 625 626 /* 627 * Destructively split a string into fields separated by white space. 628 * `#' at the beginning of a field begins a comment that extends to the 629 * end of the string. Fields may be quoted with `"'. Inside quoted 630 * strings, the backslash escapes `\"' and `\\' are honored. 631 * 632 * Pointers to up to the first maxfields fields are stored in the fields 633 * array. Missing fields get NULL pointers. 634 * 635 * The return value is the actual number of fields parsed, and is always 636 * <= maxfields. 637 * 638 * On a syntax error, places a message in the msg string, and returns -1. 639 */ 640 static int 641 split(char *str, char *fields[], int maxfields, char *msg, size_t msglen) 642 { 643 char *p; 644 int i; 645 static const char ws[] = " \t"; 646 647 for (i = 0; i < maxfields; i++) 648 fields[i] = NULL; 649 p = str; 650 i = 0; 651 while (*p != '\0') { 652 p += strspn(p, ws); 653 if (*p == '#' || *p == '\0') 654 break; 655 if (i >= maxfields) { 656 snprintf(msg, msglen, "line has too many fields"); 657 return -1; 658 } 659 if (*p == '"') { 660 char *dst; 661 662 dst = ++p; 663 fields[i] = dst; 664 while (*p != '"') { 665 if (*p == '\\') { 666 p++; 667 if (*p != '"' && *p != '\\' && 668 *p != '\0') { 669 snprintf(msg, msglen, 670 "invalid `\\' escape"); 671 return -1; 672 } 673 } 674 if (*p == '\0') { 675 snprintf(msg, msglen, 676 "unterminated quoted string"); 677 return -1; 678 } 679 *dst++ = *p++; 680 } 681 *dst = '\0'; 682 p++; 683 if (*p != '\0' && strspn(p, ws) == 0) { 684 snprintf(msg, msglen, "quoted string not" 685 " followed by white space"); 686 return -1; 687 } 688 } else { 689 fields[i] = p; 690 p += strcspn(p, ws); 691 if (*p != '\0') 692 *p++ = '\0'; 693 } 694 i++; 695 } 696 return i; 697 } 698 699 int 700 tac_add_server(struct tac_handle *h, const char *host, int port, 701 const char *secret, int timeout, int flags) 702 { 703 struct tac_server *srvp; 704 705 if (h->num_servers >= MAXSERVERS) { 706 generr(h, "Too many TACACS+ servers specified"); 707 return -1; 708 } 709 srvp = &h->servers[h->num_servers]; 710 711 memset(&srvp->addr, 0, sizeof srvp->addr); 712 srvp->addr.sin_len = sizeof srvp->addr; 713 srvp->addr.sin_family = AF_INET; 714 if (!inet_aton(host, &srvp->addr.sin_addr)) { 715 struct hostent *hent; 716 717 if ((hent = gethostbyname(host)) == NULL) { 718 generr(h, "%s: host not found", host); 719 return -1; 720 } 721 memcpy(&srvp->addr.sin_addr, hent->h_addr, 722 sizeof srvp->addr.sin_addr); 723 } 724 srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT); 725 if ((srvp->secret = xstrdup(h, secret)) == NULL) 726 return -1; 727 srvp->timeout = timeout; 728 srvp->flags = flags; 729 h->num_servers++; 730 return 0; 731 } 732 733 void 734 tac_close(struct tac_handle *h) 735 { 736 int srv; 737 738 if (h->fd != -1) 739 close(h->fd); 740 for (srv = 0; srv < h->num_servers; srv++) { 741 memset(h->servers[srv].secret, 0, 742 strlen(h->servers[srv].secret)); 743 free(h->servers[srv].secret); 744 } 745 free_str(&h->user); 746 free_str(&h->port); 747 free_str(&h->rem_addr); 748 free_str(&h->data); 749 free_str(&h->user_msg); 750 free(h); 751 } 752 753 int 754 tac_config(struct tac_handle *h, const char *path) 755 { 756 FILE *fp; 757 char buf[MAXCONFLINE]; 758 int linenum; 759 int retval; 760 761 if (path == NULL) 762 path = PATH_TACPLUS_CONF; 763 if ((fp = fopen(path, "r")) == NULL) { 764 generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); 765 return -1; 766 } 767 retval = 0; 768 linenum = 0; 769 while (fgets(buf, sizeof buf, fp) != NULL) { 770 int len; 771 char *fields[4]; 772 int nfields; 773 char msg[ERRSIZE]; 774 char *host; 775 char *port_str; 776 char *secret; 777 char *timeout_str; 778 char *options_str; 779 char *end; 780 unsigned long timeout; 781 int port; 782 int options; 783 784 linenum++; 785 len = strlen(buf); 786 /* We know len > 0, else fgets would have returned NULL. */ 787 if (buf[len - 1] != '\n') { 788 if (len == sizeof buf - 1) 789 generr(h, "%s:%d: line too long", path, 790 linenum); 791 else 792 generr(h, "%s:%d: missing newline", path, 793 linenum); 794 retval = -1; 795 break; 796 } 797 buf[len - 1] = '\0'; 798 799 /* Extract the fields from the line. */ 800 nfields = split(buf, fields, 4, msg, sizeof msg); 801 if (nfields == -1) { 802 generr(h, "%s:%d: %s", path, linenum, msg); 803 retval = -1; 804 break; 805 } 806 if (nfields == 0) 807 continue; 808 if (nfields < 2) { 809 generr(h, "%s:%d: missing shared secret", path, 810 linenum); 811 retval = -1; 812 break; 813 } 814 host = fields[0]; 815 secret = fields[1]; 816 timeout_str = fields[2]; 817 options_str = fields[3]; 818 819 /* Parse and validate the fields. */ 820 host = strtok(host, ":"); 821 port_str = strtok(NULL, ":"); 822 if (port_str != NULL) { 823 port = strtoul(port_str, &end, 10); 824 if (port_str[0] == '\0' || *end != '\0') { 825 generr(h, "%s:%d: invalid port", path, 826 linenum); 827 retval = -1; 828 break; 829 } 830 } else 831 port = 0; 832 if (timeout_str != NULL) { 833 timeout = strtoul(timeout_str, &end, 10); 834 if (timeout_str[0] == '\0' || *end != '\0') { 835 generr(h, "%s:%d: invalid timeout", path, 836 linenum); 837 retval = -1; 838 break; 839 } 840 } else 841 timeout = TIMEOUT; 842 options = 0; 843 if (options_str != NULL) { 844 if (strcmp(options_str, "single-connection") == 0) 845 options |= TAC_SRVR_SINGLE_CONNECT; 846 else { 847 generr(h, "%s:%d: invalid option \"%s\"", 848 path, linenum, options_str); 849 retval = -1; 850 break; 851 } 852 }; 853 854 if (tac_add_server(h, host, port, secret, timeout, 855 options) == -1) { 856 char msg[ERRSIZE]; 857 858 strcpy(msg, h->errmsg); 859 generr(h, "%s:%d: %s", path, linenum, msg); 860 retval = -1; 861 break; 862 } 863 } 864 /* Clear out the buffer to wipe a possible copy of a shared secret */ 865 memset(buf, 0, sizeof buf); 866 fclose(fp); 867 return retval; 868 } 869 870 int 871 tac_create_authen(struct tac_handle *h, int action, int type, int service) 872 { 873 struct tac_msg *msg; 874 struct tac_authen_start *as; 875 876 h->last_seq_no = 0; 877 878 msg = &h->request; 879 msg->type = TAC_AUTHEN; 880 msg->version = authen_version(action, type); 881 msg->flags = 0; 882 883 as = &msg->u.authen_start; 884 as->action = action; 885 as->priv_lvl = TAC_PRIV_LVL_USER; 886 as->authen_type = type; 887 as->service = service; 888 889 free_str(&h->user); 890 free_str(&h->port); 891 free_str(&h->rem_addr); 892 free_str(&h->data); 893 free_str(&h->user_msg); 894 895 /* XXX - more to do */ 896 return 0; 897 } 898 899 void * 900 tac_get_data(struct tac_handle *h, size_t *len) 901 { 902 return dup_str(h, &h->srvr_data, len); 903 } 904 905 char * 906 tac_get_msg(struct tac_handle *h) 907 { 908 return (char *)dup_str(h, &h->srvr_msg, NULL); 909 } 910 911 /* 912 * Create and initialize a tac_handle structure, and return it to the 913 * caller. Can fail only if the necessary memory cannot be allocated. 914 * In that case, it returns NULL. 915 */ 916 struct tac_handle * 917 tac_open(void) 918 { 919 struct tac_handle *h; 920 921 h = (struct tac_handle *)malloc(sizeof(struct tac_handle)); 922 if (h != NULL) { 923 h->fd = -1; 924 h->num_servers = 0; 925 h->cur_server = 0; 926 h->errmsg[0] = '\0'; 927 init_clnt_str(&h->user); 928 init_clnt_str(&h->port); 929 init_clnt_str(&h->rem_addr); 930 init_clnt_str(&h->data); 931 init_clnt_str(&h->user_msg); 932 init_srvr_str(&h->srvr_msg); 933 init_srvr_str(&h->srvr_data); 934 srandomdev(); 935 } 936 return h; 937 } 938 939 int 940 tac_send_authen(struct tac_handle *h) 941 { 942 struct tac_authen_reply *ar; 943 944 if (h->last_seq_no == 0) { /* Authentication START packet */ 945 struct tac_authen_start *as; 946 947 as = &h->request.u.authen_start; 948 h->request.length = 949 htonl(offsetof(struct tac_authen_start, rest[0])); 950 if (add_str_8(h, &as->user_len, &h->user) == -1 || 951 add_str_8(h, &as->port_len, &h->port) == -1 || 952 add_str_8(h, &as->rem_addr_len, &h->rem_addr) == -1 || 953 add_str_8(h, &as->data_len, &h->data) == -1) 954 return -1; 955 } else { /* Authentication CONTINUE packet */ 956 struct tac_authen_cont *ac; 957 958 ac = &h->request.u.authen_cont; 959 ac->flags = 0; 960 h->request.length = 961 htonl(offsetof(struct tac_authen_cont, rest[0])); 962 if (add_str_16(h, &ac->user_msg_len, &h->user_msg) == -1 || 963 add_str_16(h, &ac->data_len, &h->data) == -1) 964 return -1; 965 } 966 967 /* Send the message and retrieve the reply. */ 968 if (send_msg(h) == -1 || recv_msg(h) == -1) 969 return -1; 970 971 /* Scan the optional fields in the reply. */ 972 ar = &h->response.u.authen_reply; 973 h->srvr_pos = offsetof(struct tac_authen_reply, rest[0]); 974 if (get_srvr_str(h, &h->srvr_msg, ntohs(ar->msg_len)) == -1 || 975 get_srvr_str(h, &h->srvr_data, ntohs(ar->data_len)) == -1 || 976 get_srvr_end(h) == -1) 977 return -1; 978 979 if (!h->single_connect && 980 ar->status != TAC_AUTHEN_STATUS_GETDATA && 981 ar->status != TAC_AUTHEN_STATUS_GETUSER && 982 ar->status != TAC_AUTHEN_STATUS_GETPASS) 983 close_connection(h); 984 985 return ar->flags << 8 | ar->status; 986 } 987 988 int 989 tac_set_rem_addr(struct tac_handle *h, const char *addr) 990 { 991 return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0); 992 } 993 994 int 995 tac_set_data(struct tac_handle *h, const void *data, size_t data_len) 996 { 997 return save_str(h, &h->data, data, data_len); 998 } 999 1000 int 1001 tac_set_msg(struct tac_handle *h, const char *msg) 1002 { 1003 return save_str(h, &h->user_msg, msg, msg != NULL ? strlen(msg) : 0); 1004 } 1005 1006 int 1007 tac_set_port(struct tac_handle *h, const char *port) 1008 { 1009 return save_str(h, &h->port, port, port != NULL ? strlen(port) : 0); 1010 } 1011 1012 int 1013 tac_set_priv(struct tac_handle *h, int priv) 1014 { 1015 if (!(TAC_PRIV_LVL_MIN <= priv && priv <= TAC_PRIV_LVL_MAX)) { 1016 generr(h, "Attempt to set invalid privilege level"); 1017 return -1; 1018 } 1019 h->request.u.authen_start.priv_lvl = priv; 1020 return 0; 1021 } 1022 1023 int 1024 tac_set_user(struct tac_handle *h, const char *user) 1025 { 1026 return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0); 1027 } 1028 1029 const char * 1030 tac_strerror(struct tac_handle *h) 1031 { 1032 return h->errmsg; 1033 } 1034 1035 static void * 1036 xmalloc(struct tac_handle *h, size_t size) 1037 { 1038 void *r; 1039 1040 if ((r = malloc(size)) == NULL) 1041 generr(h, "Out of memory"); 1042 return r; 1043 } 1044 1045 static char * 1046 xstrdup(struct tac_handle *h, const char *s) 1047 { 1048 char *r; 1049 1050 if ((r = strdup(s)) == NULL) 1051 generr(h, "Out of memory"); 1052 return r; 1053 } 1054