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