taclib.c revision 141918
1169689Skan/*- 2169689Skan * Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc. 3169689Skan * All rights reserved. 4169689Skan * 5169689Skan * Redistribution and use in source and binary forms, with or without 6169689Skan * modification, are permitted provided that the following conditions 7169689Skan * are met: 8169689Skan * 1. Redistributions of source code must retain the above copyright 9169689Skan * notice, this list of conditions and the following disclaimer. 10169689Skan * 2. Redistributions in binary form must reproduce the above copyright 11169689Skan * notice, this list of conditions and the following disclaimer in the 12169689Skan * documentation and/or other materials provided with the distribution. 13169689Skan * 14169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169689Skan * SUCH DAMAGE. 25169689Skan */ 26169689Skan 27169689Skan#include <sys/cdefs.h> 28169689Skan__FBSDID("$FreeBSD: head/lib/libtacplus/taclib.c 141918 2005-02-14 17:42:58Z stefanf $"); 29169689Skan 30169689Skan#include <sys/types.h> 31169689Skan#include <sys/socket.h> 32169689Skan#include <sys/time.h> 33169689Skan#include <netinet/in.h> 34169689Skan#include <arpa/inet.h> 35169689Skan 36169689Skan#include <assert.h> 37169689Skan#include <errno.h> 38169689Skan#include <fcntl.h> 39169689Skan#include <md5.h> 40169689Skan#include <netdb.h> 41169689Skan#include <stdarg.h> 42169689Skan#include <stddef.h> 43169689Skan#include <stdio.h> 44169689Skan#include <stdlib.h> 45169689Skan#include <string.h> 46169689Skan#include <unistd.h> 47169689Skan 48169689Skan#include "taclib_private.h" 49169689Skan 50169689Skanstatic int add_str_8(struct tac_handle *, u_int8_t *, 51169689Skan struct clnt_str *); 52169689Skanstatic int add_str_16(struct tac_handle *, u_int16_t *, 53169689Skan struct clnt_str *); 54169689Skanstatic int protocol_version(int, int, int); 55169689Skanstatic void close_connection(struct tac_handle *); 56169689Skanstatic int conn_server(struct tac_handle *); 57169689Skanstatic void crypt_msg(struct tac_handle *, struct tac_msg *); 58169689Skanstatic void *dup_str(struct tac_handle *, const struct srvr_str *, 59169689Skan size_t *); 60169689Skanstatic int establish_connection(struct tac_handle *); 61169689Skanstatic void free_str(struct clnt_str *); 62169689Skanstatic void generr(struct tac_handle *, const char *, ...) 63169689Skan __printflike(2, 3); 64169689Skanstatic void gen_session_id(struct tac_msg *); 65169689Skanstatic int get_srvr_end(struct tac_handle *); 66169689Skanstatic int get_srvr_str(struct tac_handle *, const char *, 67169689Skan struct srvr_str *, size_t); 68169689Skanstatic void init_clnt_str(struct clnt_str *); 69169689Skanstatic void init_srvr_str(struct srvr_str *); 70169689Skanstatic int read_timed(struct tac_handle *, void *, size_t, 71169689Skan const struct timeval *); 72169689Skanstatic int recv_msg(struct tac_handle *); 73169689Skanstatic int save_str(struct tac_handle *, struct clnt_str *, 74169689Skan const void *, size_t); 75169689Skanstatic int send_msg(struct tac_handle *); 76169689Skanstatic int split(char *, char *[], int, char *, size_t); 77169689Skanstatic void *xmalloc(struct tac_handle *, size_t); 78169689Skanstatic char *xstrdup(struct tac_handle *, const char *); 79169689Skanstatic void clear_srvr_avs(struct tac_handle *); 80169689Skanstatic void create_msg(struct tac_handle *, int, int, int); 81169689Skan 82169689Skan/* 83169689Skan * Append some optional data to the current request, and store its 84169689Skan * length into the 8-bit field referenced by "fld". Returns 0 on 85169689Skan * success, or -1 on failure. 86169689Skan * 87169689Skan * This function also frees the "cs" string data and initializes it 88169689Skan * for the next time. 89169689Skan */ 90169689Skanstatic int 91169689Skanadd_str_8(struct tac_handle *h, u_int8_t *fld, struct clnt_str *cs) 92169689Skan{ 93169689Skan u_int16_t len; 94169689Skan 95169689Skan if (add_str_16(h, &len, cs) == -1) 96169689Skan return -1; 97169689Skan len = ntohs(len); 98169689Skan if (len > 0xff) { 99169689Skan generr(h, "Field too long"); 100169689Skan return -1; 101169689Skan } 102169689Skan *fld = len; 103169689Skan return 0; 104169689Skan} 105169689Skan 106169689Skan/* 107169689Skan * Append some optional data to the current request, and store its 108169689Skan * length into the 16-bit field (network byte order) referenced by 109169689Skan * "fld". Returns 0 on success, or -1 on failure. 110169689Skan * 111169689Skan * This function also frees the "cs" string data and initializes it 112169689Skan * for the next time. 113169689Skan */ 114169689Skanstatic int 115169689Skanadd_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs) 116169689Skan{ 117169689Skan size_t len; 118169689Skan 119169689Skan len = cs->len; 120169689Skan if (cs->data == NULL) 121169689Skan len = 0; 122169689Skan if (len != 0) { 123169689Skan int offset; 124169689Skan 125169689Skan if (len > 0xffff) { 126169689Skan generr(h, "Field too long"); 127169689Skan return -1; 128169689Skan } 129169689Skan offset = ntohl(h->request.length); 130169689Skan if (offset + len > BODYSIZE) { 131169689Skan generr(h, "Message too long"); 132169689Skan return -1; 133169689Skan } 134169689Skan memcpy(h->request.u.body + offset, cs->data, len); 135169689Skan h->request.length = htonl(offset + len); 136169689Skan } 137169689Skan *fld = htons(len); 138169689Skan free_str(cs); 139169689Skan return 0; 140169689Skan} 141169689Skan 142169689Skanstatic int 143169689Skanprotocol_version(int msg_type, int var, int type) 144169689Skan{ 145169689Skan int minor; 146169689Skan 147169689Skan switch (msg_type) { 148169689Skan case TAC_AUTHEN: 149169689Skan /* 'var' represents the 'action' */ 150169689Skan switch (var) { 151169689Skan case TAC_AUTHEN_LOGIN: 152169689Skan switch (type) { 153169689Skan 154169689Skan case TAC_AUTHEN_TYPE_PAP: 155169689Skan case TAC_AUTHEN_TYPE_CHAP: 156169689Skan case TAC_AUTHEN_TYPE_MSCHAP: 157169689Skan case TAC_AUTHEN_TYPE_ARAP: 158169689Skan minor = 1; 159169689Skan break; 160169689Skan 161169689Skan default: 162169689Skan minor = 0; 163169689Skan break; 164169689Skan } 165169689Skan break; 166169689Skan 167169689Skan case TAC_AUTHEN_SENDAUTH: 168169689Skan minor = 1; 169169689Skan break; 170169689Skan 171169689Skan default: 172169689Skan minor = 0; 173169689Skan break; 174169689Skan }; 175169689Skan break; 176169689Skan 177169689Skan case TAC_AUTHOR: 178169689Skan /* 'var' represents the 'method' */ 179169689Skan switch (var) { 180169689Skan /* 181169689Skan * When new authentication methods are added, include 'method' 182169689Skan * in determining the value of 'minor'. At this point, all 183169689Skan * methods defined in this implementation (see "Authorization 184169689Skan * authentication methods" in taclib.h) are minor version 0 185169689Skan * Not all types, however, indicate minor version 0. 186169689Skan */ 187169689Skan case TAC_AUTHEN_METH_NOT_SET: 188169689Skan case TAC_AUTHEN_METH_NONE: 189169689Skan case TAC_AUTHEN_METH_KRB5: 190169689Skan case TAC_AUTHEN_METH_LINE: 191169689Skan case TAC_AUTHEN_METH_ENABLE: 192169689Skan case TAC_AUTHEN_METH_LOCAL: 193169689Skan case TAC_AUTHEN_METH_TACACSPLUS: 194169689Skan case TAC_AUTHEN_METH_RCMD: 195169689Skan switch (type) { 196169689Skan case TAC_AUTHEN_TYPE_PAP: 197169689Skan case TAC_AUTHEN_TYPE_CHAP: 198169689Skan case TAC_AUTHEN_TYPE_MSCHAP: 199169689Skan case TAC_AUTHEN_TYPE_ARAP: 200169689Skan minor = 1; 201169689Skan break; 202169689Skan 203169689Skan default: 204169689Skan minor = 0; 205169689Skan break; 206169689Skan } 207169689Skan break; 208169689Skan default: 209169689Skan minor = 0; 210169689Skan break; 211169689Skan } 212169689Skan break; 213169689Skan 214169689Skan default: 215169689Skan minor = 0; 216169689Skan break; 217169689Skan } 218169689Skan 219169689Skan return TAC_VER_MAJOR << 4 | minor; 220169689Skan} 221169689Skan 222169689Skan 223169689Skanstatic void 224169689Skanclose_connection(struct tac_handle *h) 225169689Skan{ 226169689Skan if (h->fd != -1) { 227169689Skan close(h->fd); 228169689Skan h->fd = -1; 229169689Skan } 230169689Skan} 231169689Skan 232169689Skanstatic int 233169689Skanconn_server(struct tac_handle *h) 234169689Skan{ 235169689Skan const struct tac_server *srvp = &h->servers[h->cur_server]; 236169689Skan int flags; 237169689Skan 238169689Skan if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { 239169689Skan generr(h, "Cannot create socket: %s", strerror(errno)); 240169689Skan return -1; 241169689Skan } 242169689Skan if ((flags = fcntl(h->fd, F_GETFL, 0)) == -1 || 243169689Skan fcntl(h->fd, F_SETFL, flags | O_NONBLOCK) == -1) { 244169689Skan generr(h, "Cannot set non-blocking mode on socket: %s", 245169689Skan strerror(errno)); 246169689Skan close(h->fd); 247169689Skan h->fd = -1; 248169689Skan return -1; 249169689Skan } 250169689Skan if (connect(h->fd, (struct sockaddr *)&srvp->addr, 251169689Skan sizeof srvp->addr) == 0) 252169689Skan return 0; 253169689Skan 254169689Skan if (errno == EINPROGRESS) { 255169689Skan fd_set wfds; 256169689Skan struct timeval tv; 257169689Skan int nfds; 258169689Skan struct sockaddr peer; 259169689Skan socklen_t errlen, peerlen; 260169689Skan int err; 261169689Skan 262169689Skan /* Wait for the connection to complete. */ 263169689Skan FD_ZERO(&wfds); 264169689Skan FD_SET(h->fd, &wfds); 265169689Skan tv.tv_sec = srvp->timeout; 266169689Skan tv.tv_usec = 0; 267169689Skan nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv); 268169689Skan if (nfds == -1) { 269169689Skan generr(h, "select: %s", strerror(errno)); 270169689Skan close(h->fd); 271169689Skan h->fd = -1; 272169689Skan return -1; 273169689Skan } 274169689Skan if (nfds == 0) { 275169689Skan generr(h, "connect: timed out"); 276169689Skan close(h->fd); 277169689Skan h->fd = -1; 278169689Skan return -1; 279169689Skan } 280169689Skan 281169689Skan /* See whether we are connected now. */ 282169689Skan peerlen = sizeof peer; 283169689Skan if (getpeername(h->fd, &peer, &peerlen) == 0) 284169689Skan return 0; 285169689Skan 286169689Skan if (errno != ENOTCONN) { 287169689Skan generr(h, "getpeername: %s", strerror(errno)); 288169689Skan close(h->fd); 289169689Skan h->fd = -1; 290169689Skan return -1; 291169689Skan } 292169689Skan 293169689Skan /* Find out why the connect failed. */ 294169689Skan errlen = sizeof err; 295169689Skan getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen); 296169689Skan errno = err; 297169689Skan } 298169689Skan generr(h, "connect: %s", strerror(errno)); 299169689Skan close(h->fd); 300169689Skan h->fd = -1; 301169689Skan return -1; 302169689Skan} 303169689Skan 304169689Skan/* 305169689Skan * Encrypt or decrypt a message. The operations are symmetrical. 306169689Skan */ 307169689Skanstatic void 308169689Skancrypt_msg(struct tac_handle *h, struct tac_msg *msg) 309169689Skan{ 310169689Skan const char *secret; 311169689Skan MD5_CTX base_ctx; 312169689Skan MD5_CTX ctx; 313169689Skan unsigned char md5[16]; 314169689Skan int chunk; 315169689Skan int msg_len; 316169689Skan 317169689Skan secret = h->servers[h->cur_server].secret; 318169689Skan if (secret[0] == '\0') 319169689Skan msg->flags |= TAC_UNENCRYPTED; 320169689Skan if (msg->flags & TAC_UNENCRYPTED) 321169689Skan return; 322169689Skan 323169689Skan msg_len = ntohl(msg->length); 324169689Skan 325169689Skan MD5Init(&base_ctx); 326169689Skan MD5Update(&base_ctx, msg->session_id, sizeof msg->session_id); 327169689Skan MD5Update(&base_ctx, secret, strlen(secret)); 328169689Skan MD5Update(&base_ctx, &msg->version, sizeof msg->version); 329169689Skan MD5Update(&base_ctx, &msg->seq_no, sizeof msg->seq_no); 330169689Skan 331169689Skan ctx = base_ctx; 332169689Skan for (chunk = 0; chunk < msg_len; chunk += sizeof md5) { 333169689Skan int chunk_len; 334169689Skan int i; 335169689Skan 336169689Skan MD5Final(md5, &ctx); 337169689Skan 338169689Skan if ((chunk_len = msg_len - chunk) > sizeof md5) 339169689Skan chunk_len = sizeof md5; 340169689Skan for (i = 0; i < chunk_len; i++) 341169689Skan msg->u.body[chunk + i] ^= md5[i]; 342169689Skan 343169689Skan ctx = base_ctx; 344169689Skan MD5Update(&ctx, md5, sizeof md5); 345169689Skan } 346169689Skan} 347169689Skan 348169689Skan/* 349169689Skan * Return a dynamically allocated copy of the given server string. 350169689Skan * The copy is null-terminated. If "len" is non-NULL, the length of 351169689Skan * the string (excluding the terminating null byte) is stored via it. 352169689Skan * Returns NULL on failure. Empty strings are still allocated even 353169689Skan * though they have no content. 354169689Skan */ 355169689Skanstatic void * 356169689Skandup_str(struct tac_handle *h, const struct srvr_str *ss, size_t *len) 357169689Skan{ 358169689Skan unsigned char *p; 359169689Skan 360169689Skan if ((p = (unsigned char *)xmalloc(h, ss->len + 1)) == NULL) 361169689Skan return NULL; 362169689Skan if (ss->data != NULL && ss->len != 0) 363169689Skan memcpy(p, ss->data, ss->len); 364169689Skan p[ss->len] = '\0'; 365169689Skan if (len != NULL) 366169689Skan *len = ss->len; 367169689Skan return p; 368169689Skan} 369169689Skan 370169689Skanstatic int 371169689Skanestablish_connection(struct tac_handle *h) 372169689Skan{ 373169689Skan int i; 374169689Skan 375169689Skan if (h->fd >= 0) /* Already connected. */ 376169689Skan return 0; 377169689Skan if (h->num_servers == 0) { 378169689Skan generr(h, "No TACACS+ servers specified"); 379169689Skan return -1; 380169689Skan } 381169689Skan /* 382169689Skan * Try the servers round-robin. We begin with the one that 383169689Skan * worked for us the last time. That way, once we find a good 384169689Skan * server, we won't waste any more time trying the bad ones. 385169689Skan */ 386169689Skan for (i = 0; i < h->num_servers; i++) { 387169689Skan if (conn_server(h) == 0) { 388169689Skan h->single_connect = (h->servers[h->cur_server].flags & 389169689Skan TAC_SRVR_SINGLE_CONNECT) != 0; 390169689Skan return 0; 391169689Skan } 392169689Skan if (++h->cur_server >= h->num_servers) /* Wrap around */ 393169689Skan h->cur_server = 0; 394169689Skan } 395169689Skan /* Just return whatever error was last reported by conn_server(). */ 396169689Skan return -1; 397169689Skan} 398169689Skan 399169689Skan/* 400169689Skan * Free a client string, obliterating its contents first for security. 401169689Skan */ 402169689Skanstatic void 403169689Skanfree_str(struct clnt_str *cs) 404169689Skan{ 405169689Skan if (cs->data != NULL) { 406169689Skan memset(cs->data, 0, cs->len); 407169689Skan free(cs->data); 408169689Skan cs->data = NULL; 409169689Skan cs->len = 0; 410169689Skan } 411169689Skan} 412169689Skan 413169689Skanstatic void 414169689Skangenerr(struct tac_handle *h, const char *format, ...) 415169689Skan{ 416169689Skan va_list ap; 417169689Skan 418169689Skan va_start(ap, format); 419169689Skan vsnprintf(h->errmsg, ERRSIZE, format, ap); 420169689Skan va_end(ap); 421169689Skan} 422169689Skan 423169689Skanstatic void 424169689Skangen_session_id(struct tac_msg *msg) 425169689Skan{ 426169689Skan int r; 427169689Skan 428169689Skan r = random(); 429169689Skan msg->session_id[0] = r >> 8; 430169689Skan msg->session_id[1] = r; 431169689Skan r = random(); 432169689Skan msg->session_id[2] = r >> 8; 433169689Skan msg->session_id[3] = r; 434169689Skan} 435169689Skan 436169689Skan/* 437169689Skan * Verify that we are exactly at the end of the response message. 438169689Skan * Returns 0 on success, -1 on failure. 439169689Skan */ 440169689Skanstatic int 441169689Skanget_srvr_end(struct tac_handle *h) 442169689Skan{ 443169689Skan int len; 444169689Skan 445169689Skan len = ntohl(h->response.length); 446169689Skan 447169689Skan if (h->srvr_pos != len) { 448169689Skan generr(h, "Invalid length field in response " 449169689Skan "from server: end expected at %u, response length %u", 450169689Skan h->srvr_pos, len); 451169689Skan return -1; 452169689Skan } 453169689Skan return 0; 454169689Skan} 455169689Skan 456169689Skanstatic int 457169689Skanget_srvr_str(struct tac_handle *h, const char *field, 458169689Skan struct srvr_str *ss, size_t len) 459169689Skan{ 460169689Skan if (h->srvr_pos + len > ntohl(h->response.length)) { 461169689Skan generr(h, "Invalid length field in %s response from server " 462169689Skan "(%lu > %lu)", field, (u_long)(h->srvr_pos + len), 463169689Skan (u_long)ntohl(h->response.length)); 464169689Skan return -1; 465169689Skan } 466169689Skan ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL; 467169689Skan ss->len = len; 468169689Skan h->srvr_pos += len; 469169689Skan return 0; 470169689Skan} 471169689Skan 472169689Skanstatic void 473169689Skaninit_clnt_str(struct clnt_str *cs) 474169689Skan{ 475169689Skan cs->data = NULL; 476169689Skan cs->len = 0; 477169689Skan} 478169689Skan 479169689Skanstatic void 480169689Skaninit_srvr_str(struct srvr_str *ss) 481169689Skan{ 482169689Skan ss->data = NULL; 483169689Skan ss->len = 0; 484169689Skan} 485169689Skan 486169689Skanstatic int 487169689Skanread_timed(struct tac_handle *h, void *buf, size_t len, 488169689Skan const struct timeval *deadline) 489169689Skan{ 490169689Skan char *ptr; 491169689Skan 492169689Skan ptr = (char *)buf; 493169689Skan while (len > 0) { 494169689Skan int n; 495169689Skan 496169689Skan n = read(h->fd, ptr, len); 497169689Skan if (n == -1) { 498169689Skan struct timeval tv; 499169689Skan int nfds; 500169689Skan 501169689Skan if (errno != EAGAIN) { 502169689Skan generr(h, "Network read error: %s", 503169689Skan strerror(errno)); 504169689Skan return -1; 505169689Skan } 506169689Skan 507169689Skan /* Wait until we can read more data. */ 508169689Skan gettimeofday(&tv, NULL); 509169689Skan timersub(deadline, &tv, &tv); 510169689Skan if (tv.tv_sec >= 0) { 511169689Skan fd_set rfds; 512169689Skan 513169689Skan FD_ZERO(&rfds); 514169689Skan FD_SET(h->fd, &rfds); 515169689Skan nfds = 516169689Skan select(h->fd + 1, &rfds, NULL, NULL, &tv); 517169689Skan if (nfds == -1) { 518169689Skan generr(h, "select: %s", 519169689Skan strerror(errno)); 520169689Skan return -1; 521169689Skan } 522169689Skan } else 523169689Skan 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 */ 543static int 544recv_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 597static int 598save_str(struct tac_handle *h, struct clnt_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 */ 615static int 616send_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/* 689 * Destructively split a string into fields separated by white space. 690 * `#' at the beginning of a field begins a comment that extends to the 691 * end of the string. Fields may be quoted with `"'. Inside quoted 692 * strings, the backslash escapes `\"' and `\\' are honored. 693 * 694 * Pointers to up to the first maxfields fields are stored in the fields 695 * array. Missing fields get NULL pointers. 696 * 697 * The return value is the actual number of fields parsed, and is always 698 * <= maxfields. 699 * 700 * On a syntax error, places a message in the msg string, and returns -1. 701 */ 702static int 703split(char *str, char *fields[], int maxfields, char *msg, size_t msglen) 704{ 705 char *p; 706 int i; 707 static const char ws[] = " \t"; 708 709 for (i = 0; i < maxfields; i++) 710 fields[i] = NULL; 711 p = str; 712 i = 0; 713 while (*p != '\0') { 714 p += strspn(p, ws); 715 if (*p == '#' || *p == '\0') 716 break; 717 if (i >= maxfields) { 718 snprintf(msg, msglen, "line has too many fields"); 719 return -1; 720 } 721 if (*p == '"') { 722 char *dst; 723 724 dst = ++p; 725 fields[i] = dst; 726 while (*p != '"') { 727 if (*p == '\\') { 728 p++; 729 if (*p != '"' && *p != '\\' && 730 *p != '\0') { 731 snprintf(msg, msglen, 732 "invalid `\\' escape"); 733 return -1; 734 } 735 } 736 if (*p == '\0') { 737 snprintf(msg, msglen, 738 "unterminated quoted string"); 739 return -1; 740 } 741 *dst++ = *p++; 742 } 743 *dst = '\0'; 744 p++; 745 if (*p != '\0' && strspn(p, ws) == 0) { 746 snprintf(msg, msglen, "quoted string not" 747 " followed by white space"); 748 return -1; 749 } 750 } else { 751 fields[i] = p; 752 p += strcspn(p, ws); 753 if (*p != '\0') 754 *p++ = '\0'; 755 } 756 i++; 757 } 758 return i; 759} 760 761int 762tac_add_server(struct tac_handle *h, const char *host, int port, 763 const char *secret, int timeout, int flags) 764{ 765 struct tac_server *srvp; 766 767 if (h->num_servers >= MAXSERVERS) { 768 generr(h, "Too many TACACS+ servers specified"); 769 return -1; 770 } 771 srvp = &h->servers[h->num_servers]; 772 773 memset(&srvp->addr, 0, sizeof srvp->addr); 774 srvp->addr.sin_len = sizeof srvp->addr; 775 srvp->addr.sin_family = AF_INET; 776 if (!inet_aton(host, &srvp->addr.sin_addr)) { 777 struct hostent *hent; 778 779 if ((hent = gethostbyname(host)) == NULL) { 780 generr(h, "%s: host not found", host); 781 return -1; 782 } 783 memcpy(&srvp->addr.sin_addr, hent->h_addr, 784 sizeof srvp->addr.sin_addr); 785 } 786 srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT); 787 if ((srvp->secret = xstrdup(h, secret)) == NULL) 788 return -1; 789 srvp->timeout = timeout; 790 srvp->flags = flags; 791 h->num_servers++; 792 return 0; 793} 794 795void 796tac_close(struct tac_handle *h) 797{ 798 int i, srv; 799 800 if (h->fd != -1) 801 close(h->fd); 802 for (srv = 0; srv < h->num_servers; srv++) { 803 memset(h->servers[srv].secret, 0, 804 strlen(h->servers[srv].secret)); 805 free(h->servers[srv].secret); 806 } 807 free_str(&h->user); 808 free_str(&h->port); 809 free_str(&h->rem_addr); 810 free_str(&h->data); 811 free_str(&h->user_msg); 812 for (i=0; i<MAXAVPAIRS; i++) 813 free_str(&(h->avs[i])); 814 815 /* Clear everything else before freeing memory */ 816 memset(h, 0, sizeof(struct tac_handle)); 817 free(h); 818} 819 820int 821tac_config(struct tac_handle *h, const char *path) 822{ 823 FILE *fp; 824 char buf[MAXCONFLINE]; 825 int linenum; 826 int retval; 827 828 if (path == NULL) 829 path = PATH_TACPLUS_CONF; 830 if ((fp = fopen(path, "r")) == NULL) { 831 generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); 832 return -1; 833 } 834 retval = 0; 835 linenum = 0; 836 while (fgets(buf, sizeof buf, fp) != NULL) { 837 int len; 838 char *fields[4]; 839 int nfields; 840 char msg[ERRSIZE]; 841 char *host, *res; 842 char *port_str; 843 char *secret; 844 char *timeout_str; 845 char *options_str; 846 char *end; 847 unsigned long timeout; 848 int port; 849 int options; 850 851 linenum++; 852 len = strlen(buf); 853 /* We know len > 0, else fgets would have returned NULL. */ 854 if (buf[len - 1] != '\n') { 855 if (len >= sizeof buf - 1) 856 generr(h, "%s:%d: line too long", path, 857 linenum); 858 else 859 generr(h, "%s:%d: missing newline", path, 860 linenum); 861 retval = -1; 862 break; 863 } 864 buf[len - 1] = '\0'; 865 866 /* Extract the fields from the line. */ 867 nfields = split(buf, fields, 4, msg, sizeof msg); 868 if (nfields == -1) { 869 generr(h, "%s:%d: %s", path, linenum, msg); 870 retval = -1; 871 break; 872 } 873 if (nfields == 0) 874 continue; 875 if (nfields < 2) { 876 generr(h, "%s:%d: missing shared secret", path, 877 linenum); 878 retval = -1; 879 break; 880 } 881 host = fields[0]; 882 secret = fields[1]; 883 timeout_str = fields[2]; 884 options_str = fields[3]; 885 886 /* Parse and validate the fields. */ 887 res = host; 888 host = strsep(&res, ":"); 889 port_str = strsep(&res, ":"); 890 if (port_str != NULL) { 891 port = strtoul(port_str, &end, 10); 892 if (port_str[0] == '\0' || *end != '\0') { 893 generr(h, "%s:%d: invalid port", path, 894 linenum); 895 retval = -1; 896 break; 897 } 898 } else 899 port = 0; 900 if (timeout_str != NULL) { 901 timeout = strtoul(timeout_str, &end, 10); 902 if (timeout_str[0] == '\0' || *end != '\0') { 903 generr(h, "%s:%d: invalid timeout", path, 904 linenum); 905 retval = -1; 906 break; 907 } 908 } else 909 timeout = TIMEOUT; 910 options = 0; 911 if (options_str != NULL) { 912 if (strcmp(options_str, "single-connection") == 0) 913 options |= TAC_SRVR_SINGLE_CONNECT; 914 else { 915 generr(h, "%s:%d: invalid option \"%s\"", 916 path, linenum, options_str); 917 retval = -1; 918 break; 919 } 920 }; 921 922 if (tac_add_server(h, host, port, secret, timeout, 923 options) == -1) { 924 char msg[ERRSIZE]; 925 926 strcpy(msg, h->errmsg); 927 generr(h, "%s:%d: %s", path, linenum, msg); 928 retval = -1; 929 break; 930 } 931 } 932 /* Clear out the buffer to wipe a possible copy of a shared secret */ 933 memset(buf, 0, sizeof buf); 934 fclose(fp); 935 return retval; 936} 937 938int 939tac_create_authen(struct tac_handle *h, int action, int type, int service) 940{ 941 struct tac_authen_start *as; 942 943 create_msg(h, TAC_AUTHEN, action, type); 944 945 as = &h->request.u.authen_start; 946 as->action = action; 947 as->priv_lvl = TAC_PRIV_LVL_USER; 948 as->authen_type = type; 949 as->service = service; 950 951 return 0; 952} 953 954int 955tac_create_author(struct tac_handle *h, int method, int type, int service) 956{ 957 struct tac_author_request *areq; 958 959 create_msg(h, TAC_AUTHOR, method, type); 960 961 areq = &h->request.u.author_request; 962 areq->authen_meth = method; 963 areq->priv_lvl = TAC_PRIV_LVL_USER; 964 areq->authen_type = type; 965 areq->service = service; 966 967 return 0; 968} 969 970static void 971create_msg(struct tac_handle *h, int msg_type, int var, int type) 972{ 973 struct tac_msg *msg; 974 int i; 975 976 h->last_seq_no = 0; 977 978 msg = &h->request; 979 msg->type = msg_type; 980 msg->version = protocol_version(msg_type, var, type); 981 msg->flags = 0; /* encrypted packet body */ 982 983 free_str(&h->user); 984 free_str(&h->port); 985 free_str(&h->rem_addr); 986 free_str(&h->data); 987 free_str(&h->user_msg); 988 989 for (i=0; i<MAXAVPAIRS; i++) 990 free_str(&(h->avs[i])); 991} 992 993void * 994tac_get_data(struct tac_handle *h, size_t *len) 995{ 996 return dup_str(h, &h->srvr_data, len); 997} 998 999char * 1000tac_get_msg(struct tac_handle *h) 1001{ 1002 return dup_str(h, &h->srvr_msg, NULL); 1003} 1004 1005/* 1006 * Create and initialize a tac_handle structure, and return it to the 1007 * caller. Can fail only if the necessary memory cannot be allocated. 1008 * In that case, it returns NULL. 1009 */ 1010struct tac_handle * 1011tac_open(void) 1012{ 1013 int i; 1014 struct tac_handle *h; 1015 1016 h = (struct tac_handle *)malloc(sizeof(struct tac_handle)); 1017 if (h != NULL) { 1018 h->fd = -1; 1019 h->num_servers = 0; 1020 h->cur_server = 0; 1021 h->errmsg[0] = '\0'; 1022 init_clnt_str(&h->user); 1023 init_clnt_str(&h->port); 1024 init_clnt_str(&h->rem_addr); 1025 init_clnt_str(&h->data); 1026 init_clnt_str(&h->user_msg); 1027 for (i=0; i<MAXAVPAIRS; i++) { 1028 init_clnt_str(&(h->avs[i])); 1029 init_srvr_str(&(h->srvr_avs[i])); 1030 } 1031 init_srvr_str(&h->srvr_msg); 1032 init_srvr_str(&h->srvr_data); 1033 srandomdev(); 1034 } 1035 return h; 1036} 1037 1038int 1039tac_send_authen(struct tac_handle *h) 1040{ 1041 struct tac_authen_reply *ar; 1042 1043 if (h->num_servers == 0) 1044 return -1; 1045 1046 if (h->last_seq_no == 0) { /* Authentication START packet */ 1047 struct tac_authen_start *as; 1048 1049 as = &h->request.u.authen_start; 1050 h->request.length = 1051 htonl(offsetof(struct tac_authen_start, rest[0])); 1052 if (add_str_8(h, &as->user_len, &h->user) == -1 || 1053 add_str_8(h, &as->port_len, &h->port) == -1 || 1054 add_str_8(h, &as->rem_addr_len, &h->rem_addr) == -1 || 1055 add_str_8(h, &as->data_len, &h->data) == -1) 1056 return -1; 1057 } else { /* Authentication CONTINUE packet */ 1058 struct tac_authen_cont *ac; 1059 1060 ac = &h->request.u.authen_cont; 1061 ac->flags = 0; 1062 h->request.length = 1063 htonl(offsetof(struct tac_authen_cont, rest[0])); 1064 if (add_str_16(h, &ac->user_msg_len, &h->user_msg) == -1 || 1065 add_str_16(h, &ac->data_len, &h->data) == -1) 1066 return -1; 1067 } 1068 1069 /* Send the message and retrieve the reply. */ 1070 if (send_msg(h) == -1 || recv_msg(h) == -1) 1071 return -1; 1072 1073 /* Scan the optional fields in the reply. */ 1074 ar = &h->response.u.authen_reply; 1075 h->srvr_pos = offsetof(struct tac_authen_reply, rest[0]); 1076 if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ar->msg_len)) == -1 || 1077 get_srvr_str(h, "data", &h->srvr_data, ntohs(ar->data_len)) == -1 || 1078 get_srvr_end(h) == -1) 1079 return -1; 1080 1081 if (!h->single_connect && 1082 ar->status != TAC_AUTHEN_STATUS_GETDATA && 1083 ar->status != TAC_AUTHEN_STATUS_GETUSER && 1084 ar->status != TAC_AUTHEN_STATUS_GETPASS) 1085 close_connection(h); 1086 1087 return ar->flags << 8 | ar->status; 1088} 1089 1090int 1091tac_send_author(struct tac_handle *h) 1092{ 1093 int i, current; 1094 char dbgstr[64]; 1095 struct tac_author_request *areq = &h->request.u.author_request; 1096 struct tac_author_response *ares = &h->response.u.author_response; 1097 1098 h->request.length = 1099 htonl(offsetof(struct tac_author_request, rest[0])); 1100 1101 /* Count each specified AV pair */ 1102 for (areq->av_cnt=0, i=0; i<MAXAVPAIRS; i++) 1103 if (h->avs[i].len && h->avs[i].data) 1104 areq->av_cnt++; 1105 1106 /* 1107 * Each AV size is a byte starting right after 'av_cnt'. Update the 1108 * offset to include these AV sizes. 1109 */ 1110 h->request.length = ntohl(htonl(h->request.length) + areq->av_cnt); 1111 1112 /* Now add the string arguments from 'h' */ 1113 if (add_str_8(h, &areq->user_len, &h->user) == -1 || 1114 add_str_8(h, &areq->port_len, &h->port) == -1 || 1115 add_str_8(h, &areq->rem_addr_len, &h->rem_addr) == -1) 1116 return -1; 1117 1118 /* Add each AV pair, the size of each placed in areq->rest[current] */ 1119 for (current=0, i=0; i<MAXAVPAIRS; i++) { 1120 if (h->avs[i].len && h->avs[i].data) { 1121 if (add_str_8(h, &areq->rest[current++], 1122 &(h->avs[i])) == -1) 1123 return -1; 1124 } 1125 } 1126 1127 /* Send the message and retrieve the reply. */ 1128 if (send_msg(h) == -1 || recv_msg(h) == -1) 1129 return -1; 1130 1131 /* Update the offset in the response packet based on av pairs count */ 1132 h->srvr_pos = offsetof(struct tac_author_response, rest[0]) + 1133 ares->av_cnt; 1134 1135 /* Scan the optional fields in the response. */ 1136 if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ares->msg_len)) == -1 || 1137 get_srvr_str(h, "data", &h->srvr_data, ntohs(ares->data_len)) ==-1) 1138 return -1; 1139 1140 /* Get each AV pair (just setting pointers, not malloc'ing) */ 1141 clear_srvr_avs(h); 1142 for (i=0; i<ares->av_cnt; i++) { 1143 snprintf(dbgstr, sizeof dbgstr, "av-pair-%d", i); 1144 if (get_srvr_str(h, dbgstr, &(h->srvr_avs[i]), 1145 ares->rest[i]) == -1) 1146 return -1; 1147 } 1148 1149 /* Should have ended up at the end */ 1150 if (get_srvr_end(h) == -1) 1151 return -1; 1152 1153 /* Sanity checks */ 1154 if (!h->single_connect) 1155 close_connection(h); 1156 1157 return ares->av_cnt << 8 | ares->status; 1158} 1159 1160int 1161tac_set_rem_addr(struct tac_handle *h, const char *addr) 1162{ 1163 return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0); 1164} 1165 1166int 1167tac_set_data(struct tac_handle *h, const void *data, size_t data_len) 1168{ 1169 return save_str(h, &h->data, data, data_len); 1170} 1171 1172int 1173tac_set_msg(struct tac_handle *h, const char *msg) 1174{ 1175 return save_str(h, &h->user_msg, msg, msg != NULL ? strlen(msg) : 0); 1176} 1177 1178int 1179tac_set_port(struct tac_handle *h, const char *port) 1180{ 1181 return save_str(h, &h->port, port, port != NULL ? strlen(port) : 0); 1182} 1183 1184int 1185tac_set_priv(struct tac_handle *h, int priv) 1186{ 1187 if (!(TAC_PRIV_LVL_MIN <= priv && priv <= TAC_PRIV_LVL_MAX)) { 1188 generr(h, "Attempt to set invalid privilege level"); 1189 return -1; 1190 } 1191 h->request.u.authen_start.priv_lvl = priv; 1192 return 0; 1193} 1194 1195int 1196tac_set_user(struct tac_handle *h, const char *user) 1197{ 1198 return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0); 1199} 1200 1201int 1202tac_set_av(struct tac_handle *h, u_int index, const char *av) 1203{ 1204 if (index >= MAXAVPAIRS) 1205 return -1; 1206 return save_str(h, &(h->avs[index]), av, av != NULL ? strlen(av) : 0); 1207} 1208 1209char * 1210tac_get_av(struct tac_handle *h, u_int index) 1211{ 1212 if (index >= MAXAVPAIRS) 1213 return NULL; 1214 return dup_str(h, &(h->srvr_avs[index]), NULL); 1215} 1216 1217char * 1218tac_get_av_value(struct tac_handle *h, const char *attribute) 1219{ 1220 int i, len; 1221 const char *ch, *end; 1222 const char *candidate; 1223 int candidate_len; 1224 int found_seperator; 1225 struct srvr_str srvr; 1226 1227 if (attribute == NULL || ((len = strlen(attribute)) == 0)) 1228 return NULL; 1229 1230 for (i=0; i<MAXAVPAIRS; i++) { 1231 candidate = h->srvr_avs[i].data; 1232 candidate_len = h->srvr_avs[i].len; 1233 1234 /* 1235 * Valid 'srvr_avs' guaranteed to be contiguous starting at 1236 * index 0 (not necessarily the case with 'avs'). Break out 1237 * when the "end" of the list has been reached. 1238 */ 1239 if (!candidate) 1240 break; 1241 1242 if (len < candidate_len && 1243 !strncmp(candidate, attribute, len)) { 1244 1245 ch = candidate + len; 1246 end = candidate + candidate_len; 1247 1248 /* 1249 * Sift out the white space between A and V (should not 1250 * be any, but don't trust implementation of server...) 1251 */ 1252 found_seperator = 0; 1253 while ((*ch == '=' || *ch == '*' || *ch == ' ' || 1254 *ch == '\t') && ch != end) { 1255 if (*ch == '=' || *ch == '*') 1256 found_seperator++; 1257 ch++; 1258 } 1259 1260 /* 1261 * Note: 1262 * The case of 'attribute' == "foo" and 1263 * h->srvr_avs[0] = "foobie=var1" 1264 * h->srvr_avs[1] = "foo=var2" 1265 * is handled. 1266 */ 1267 if (found_seperator == 1 && ch != end) { 1268 srvr.len = end - ch; 1269 srvr.data = ch; 1270 return dup_str(h, &srvr, NULL); 1271 } 1272 } 1273 } 1274 return NULL; 1275} 1276 1277void 1278tac_clear_avs(struct tac_handle *h) 1279{ 1280 int i; 1281 for (i=0; i<MAXAVPAIRS; i++) 1282 save_str(h, &(h->avs[i]), NULL, 0); 1283} 1284 1285static void 1286clear_srvr_avs(struct tac_handle *h) 1287{ 1288 int i; 1289 for (i=0; i<MAXAVPAIRS; i++) 1290 init_srvr_str(&(h->srvr_avs[i])); 1291} 1292 1293 1294const char * 1295tac_strerror(struct tac_handle *h) 1296{ 1297 return h->errmsg; 1298} 1299 1300static void * 1301xmalloc(struct tac_handle *h, size_t size) 1302{ 1303 void *r; 1304 1305 if ((r = malloc(size)) == NULL) 1306 generr(h, "Out of memory"); 1307 return r; 1308} 1309 1310static char * 1311xstrdup(struct tac_handle *h, const char *s) 1312{ 1313 char *r; 1314 1315 if ((r = strdup(s)) == NULL) 1316 generr(h, "Out of memory"); 1317 return r; 1318} 1319