2 * Copyright 1998 Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
48 #include "taclib_private.h"
50 static int add_str_8(struct tac_handle *, u_int8_t *,
52 static int add_str_16(struct tac_handle *, u_int16_t *,
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 *,
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 *, ...)
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 *,
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 *);
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.
85 * This function also frees the "cs" string data and initializes it
89 add_str_8(struct tac_handle *h, u_int8_t *fld, struct clnt_str *cs)
93 if (add_str_16(h, &len, cs) == -1)
97 generr(h, "Field too long");
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.
109 * This function also frees the "cs" string data and initializes it
113 add_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs)
118 if (cs->data == NULL)
124 generr(h, "Field too long");
127 offset = ntohl(h->request.length);
128 if (offset + len > BODYSIZE) {
129 generr(h, "Message too long");
132 memcpy(h->request.u.body + offset, cs->data, len);
133 h->request.length = htonl(offset + len);
141 authen_version(int action, int type)
147 case TAC_AUTHEN_LOGIN:
150 case TAC_AUTHEN_TYPE_PAP:
151 case TAC_AUTHEN_TYPE_CHAP:
152 case TAC_AUTHEN_TYPE_MSCHAP:
153 case TAC_AUTHEN_TYPE_ARAP:
163 case TAC_AUTHEN_SENDAUTH:
172 return TAC_VER_MAJOR << 4 | minor;
176 close_connection(struct tac_handle *h)
185 conn_server(struct tac_handle *h)
187 const struct tac_server *srvp = &h->servers[h->cur_server];
190 if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
191 generr(h, "Cannot create socket: %s", strerror(errno));
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",
202 if (connect(h->fd, (struct sockaddr *)&srvp->addr,
203 sizeof srvp->addr) == 0)
206 if (errno == EINPROGRESS) {
210 struct sockaddr peer;
215 /* Wait for the connection to complete. */
217 FD_SET(h->fd, &wfds);
218 tv.tv_sec = srvp->timeout;
220 nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv);
222 generr(h, "select: %s", strerror(errno));
228 generr(h, "connect: timed out");
234 /* See whether we are connected now. */
235 peerlen = sizeof peer;
236 if (getpeername(h->fd, &peer, &peerlen) == 0)
239 if (errno != ENOTCONN) {
240 generr(h, "getpeername: %s", strerror(errno));
246 /* Find out why the connect failed. */
248 getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
251 generr(h, "connect: %s", strerror(errno));
258 * Encrypt or decrypt a message. The operations are symmetrical.
261 crypt_msg(struct tac_handle *h, struct tac_msg *msg)
266 unsigned char md5[16];
270 secret = h->servers[h->cur_server].secret;
271 if (secret[0] == '\0')
272 msg->flags |= TAC_UNENCRYPTED;
273 if (msg->flags & TAC_UNENCRYPTED)
276 msg_len = ntohl(msg->length);
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);
285 for (chunk = 0; chunk < msg_len; chunk += sizeof md5) {
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];
297 MD5Update(&ctx, md5, sizeof md5);
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.
309 dup_str(struct tac_handle *h, const struct srvr_str *ss, size_t *len)
313 if ((p = (unsigned char *)xmalloc(h, ss->len + 1)) == NULL)
315 if (ss->data != NULL && ss->len != 0)
316 memcpy(p, ss->data, ss->len);
324 establish_connection(struct tac_handle *h)
328 if (h->fd >= 0) /* Already connected. */
330 if (h->num_servers == 0) {
331 generr(h, "No TACACS+ servers specified");
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.
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;
345 if (++h->cur_server >= h->num_servers) /* Wrap around */
348 /* Just return whatever error was last reported by conn_server(). */
353 * Free a client string, obliterating its contents first for security.
356 free_str(struct clnt_str *cs)
358 if (cs->data != NULL) {
359 memset(cs->data, 0, cs->len);
367 generr(struct tac_handle *h, const char *format, ...)
371 va_start(ap, format);
372 vsnprintf(h->errmsg, ERRSIZE, format, ap);
377 gen_session_id(struct tac_msg *msg)
382 msg->session_id[0] = r >> 8;
383 msg->session_id[1] = r;
385 msg->session_id[2] = r >> 8;
386 msg->session_id[3] = r;
390 * Verify that we are exactly at the end of the response message.
391 * Returns 0 on success, -1 on failure.
394 get_srvr_end(struct tac_handle *h)
396 if (h->srvr_pos != ntohl(h->response.length)) {
397 generr(h, "Invalid length field in response from server");
404 get_srvr_str(struct tac_handle *h, struct srvr_str *ss, size_t len)
406 if (h->srvr_pos + len > ntohl(h->response.length)) {
407 generr(h, "Invalid length field in response from server");
410 ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL;
417 init_clnt_str(struct clnt_str *cs)
424 init_srvr_str(struct srvr_str *ss)
431 read_timed(struct tac_handle *h, void *buf, size_t len,
432 const struct timeval *deadline)
440 n = read(h->fd, ptr, len);
445 if (errno != EAGAIN) {
446 generr(h, "Network read error: %s",
451 /* Wait until we can read more data. */
452 gettimeofday(&tv, NULL);
453 timersub(deadline, &tv, &tv);
454 if (tv.tv_sec >= 0) {
458 FD_SET(h->fd, &rfds);
460 select(h->fd + 1, &rfds, NULL, NULL, &tv);
462 generr(h, "select: %s",
469 generr(h, "Network read timed out");
473 generr(h, "unexpected EOF from server");
484 * Receive a response from the server and decrypt it. Returns 0 on
485 * success, or -1 on failure.
488 recv_msg(struct tac_handle *h)
490 struct timeval deadline;
495 gettimeofday(&deadline, NULL);
496 deadline.tv_sec += h->servers[h->cur_server].timeout;
498 /* Read the message header and make sure it is reasonable. */
499 if (read_timed(h, msg, HDRSIZE, &deadline) == -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");
506 if (msg->type != h->request.type) {
507 generr(h, "Invalid type in received message");
510 len = ntohl(msg->length);
511 if (len > BODYSIZE) {
512 generr(h, "Received message too large");
515 if (msg->seq_no != ++h->last_seq_no) {
516 generr(h, "Invalid sequence number in received message");
520 /* Read the message body. */
521 if (read_timed(h, msg->u.body, len, &deadline) == -1)
528 * Turn off single-connection mode if the server isn't amenable
531 if (!(msg->flags & TAC_SINGLE_CONNECT))
532 h->single_connect = 0;
537 save_str(struct tac_handle *h, struct clnt_str *cs, const void *data,
541 if (data != NULL && len != 0) {
542 if ((cs->data = xmalloc(h, len)) == NULL)
545 memcpy(cs->data, data, len);
551 * Send the current request, after encrypting it. Returns 0 on success,
555 send_msg(struct tac_handle *h)
557 struct timeval deadline;
562 if (h->last_seq_no & 1) {
563 generr(h, "Attempt to send message out of sequence");
568 msg->seq_no = ++h->last_seq_no;
569 if (msg->seq_no == 1)
573 if (establish_connection(h) == -1)
576 if (h->single_connect)
577 msg->flags |= TAC_SINGLE_CONNECT;
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);
587 n = write(h->fd, ptr, len);
592 if (errno != EAGAIN) {
593 generr(h, "Network write error: %s",
598 /* Wait until we can write more data. */
599 gettimeofday(&tv, NULL);
600 timersub(&deadline, &tv, &tv);
601 if (tv.tv_sec >= 0) {
605 FD_SET(h->fd, &wfds);
607 select(h->fd + 1, NULL, &wfds, NULL, &tv);
609 generr(h, "select: %s",
616 generr(h, "Network write timed out");
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.
633 * Pointers to up to the first maxfields fields are stored in the fields
634 * array. Missing fields get NULL pointers.
636 * The return value is the actual number of fields parsed, and is always
639 * On a syntax error, places a message in the msg string, and returns -1.
642 split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
646 static const char ws[] = " \t";
648 for (i = 0; i < maxfields; i++)
654 if (*p == '#' || *p == '\0')
656 if (i >= maxfields) {
657 snprintf(msg, msglen, "line has too many fields");
668 if (*p != '"' && *p != '\\' &&
670 snprintf(msg, msglen,
671 "invalid `\\' escape");
676 snprintf(msg, msglen,
677 "unterminated quoted string");
684 if (*p != '\0' && strspn(p, ws) == 0) {
685 snprintf(msg, msglen, "quoted string not"
686 " followed by white space");
701 tac_add_server(struct tac_handle *h, const char *host, int port,
702 const char *secret, int timeout, int flags)
704 struct tac_server *srvp;
706 if (h->num_servers >= MAXSERVERS) {
707 generr(h, "Too many TACACS+ servers specified");
710 srvp = &h->servers[h->num_servers];
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;
718 if ((hent = gethostbyname(host)) == NULL) {
719 generr(h, "%s: host not found", host);
722 memcpy(&srvp->addr.sin_addr, hent->h_addr,
723 sizeof srvp->addr.sin_addr);
725 srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT);
726 if ((srvp->secret = xstrdup(h, secret)) == NULL)
728 srvp->timeout = timeout;
735 tac_close(struct tac_handle *h)
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);
748 free_str(&h->rem_addr);
750 free_str(&h->user_msg);
755 tac_config(struct tac_handle *h, const char *path)
758 char buf[MAXCONFLINE];
763 path = PATH_TACPLUS_CONF;
764 if ((fp = fopen(path, "r")) == NULL) {
765 generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
770 while (fgets(buf, sizeof buf, fp) != NULL) {
781 unsigned long timeout;
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,
793 generr(h, "%s:%d: missing newline", path,
800 /* Extract the fields from the line. */
801 nfields = split(buf, fields, 4, msg, sizeof msg);
803 generr(h, "%s:%d: %s", path, linenum, msg);
810 generr(h, "%s:%d: missing shared secret", path,
817 timeout_str = fields[2];
818 options_str = fields[3];
820 /* Parse and validate the fields. */
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,
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,
845 if (options_str != NULL) {
846 if (strcmp(options_str, "single-connection") == 0)
847 options |= TAC_SRVR_SINGLE_CONNECT;
849 generr(h, "%s:%d: invalid option \"%s\"",
850 path, linenum, options_str);
856 if (tac_add_server(h, host, port, secret, timeout,
860 strcpy(msg, h->errmsg);
861 generr(h, "%s:%d: %s", path, linenum, msg);
866 /* Clear out the buffer to wipe a possible copy of a shared secret */
867 memset(buf, 0, sizeof buf);
873 tac_create_authen(struct tac_handle *h, int action, int type, int service)
876 struct tac_authen_start *as;
881 msg->type = TAC_AUTHEN;
882 msg->version = authen_version(action, type);
885 as = &msg->u.authen_start;
887 as->priv_lvl = TAC_PRIV_LVL_USER;
888 as->authen_type = type;
889 as->service = service;
893 free_str(&h->rem_addr);
895 free_str(&h->user_msg);
897 /* XXX - more to do */
902 tac_get_data(struct tac_handle *h, size_t *len)
904 return dup_str(h, &h->srvr_data, len);
908 tac_get_msg(struct tac_handle *h)
910 return (char *)dup_str(h, &h->srvr_msg, NULL);
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.
921 struct tac_handle *h;
923 h = (struct tac_handle *)malloc(sizeof(struct tac_handle));
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);
942 tac_send_authen(struct tac_handle *h)
944 struct tac_authen_reply *ar;
946 if (h->last_seq_no == 0) { /* Authentication START packet */
947 struct tac_authen_start *as;
949 as = &h->request.u.authen_start;
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)
957 } else { /* Authentication CONTINUE packet */
958 struct tac_authen_cont *ac;
960 ac = &h->request.u.authen_cont;
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)
969 /* Send the message and retrieve the reply. */
970 if (send_msg(h) == -1 || recv_msg(h) == -1)
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)
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)
987 return ar->flags << 8 | ar->status;
991 tac_set_rem_addr(struct tac_handle *h, const char *addr)
993 return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0);
997 tac_set_data(struct tac_handle *h, const void *data, size_t data_len)
999 return save_str(h, &h->data, data, data_len);
1003 tac_set_msg(struct tac_handle *h, const char *msg)
1005 return save_str(h, &h->user_msg, msg, msg != NULL ? strlen(msg) : 0);
1009 tac_set_port(struct tac_handle *h, const char *port)
1011 return save_str(h, &h->port, port, port != NULL ? strlen(port) : 0);
1015 tac_set_priv(struct tac_handle *h, int priv)
1017 if (!(TAC_PRIV_LVL_MIN <= priv && priv <= TAC_PRIV_LVL_MAX)) {
1018 generr(h, "Attempt to set invalid privilege level");
1021 h->request.u.authen_start.priv_lvl = priv;
1026 tac_set_user(struct tac_handle *h, const char *user)
1028 return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0);
1032 tac_strerror(struct tac_handle *h)
1038 xmalloc(struct tac_handle *h, size_t size)
1042 if ((r = malloc(size)) == NULL)
1043 generr(h, "Out of memory");
1048 xstrdup(struct tac_handle *h, const char *s)
1052 if ((r = strdup(s)) == NULL)
1053 generr(h, "Out of memory");