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