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