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
53 static int add_str_8(struct tac_handle *, u_int8_t *,
54 struct tac_str *);
55 static int add_str_16(struct tac_handle *, u_int16_t *,
56 struct tac_str *);
57 static int protocol_version(int, int, int);
58 static void close_connection(struct tac_handle *);
59 static int conn_server(struct tac_handle *);
60 static void crypt_msg(struct tac_handle *, struct tac_msg *);
61 static void *dup_str(struct tac_handle *, const struct tac_str *,
62 size_t *);
63 static int establish_connection(struct tac_handle *);
64 static void free_str(struct tac_str *);
65 static void generr(struct tac_handle *, const char *, ...)
66 __printflike(2, 3);
67 static void gen_session_id(struct tac_msg *);
68 static int get_srvr_end(struct tac_handle *);
69 static int get_str(struct tac_handle *, const char *,
70 struct tac_str *, size_t);
71 static void init_str(struct tac_str *);
72 static int read_timed(struct tac_handle *, void *, size_t,
73 const struct timeval *);
74 static int recv_msg(struct tac_handle *);
75 static int save_str(struct tac_handle *, struct tac_str *,
76 const void *, size_t);
77 static int send_msg(struct tac_handle *);
78 static int split(char *, char *[], int, char *, size_t);
79 static void *xmalloc(struct tac_handle *, size_t);
80 static char *xstrdup(struct tac_handle *, const char *);
81 static void clear_srvr_avs(struct tac_handle *);
82 static 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 */
92 static int
add_str_8(struct tac_handle * h,u_int8_t * fld,struct tac_str * cs)93 add_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 */
116 static int
add_str_16(struct tac_handle * h,u_int16_t * fld,struct tac_str * cs)117 add_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
144 static int
protocol_version(int msg_type,int var,int type)145 protocol_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
227 static void
close_connection(struct tac_handle * h)228 close_connection(struct tac_handle *h)
229 {
230 if (h->fd != -1) {
231 close(h->fd);
232 h->fd = -1;
233 }
234 }
235
236 static int
conn_server(struct tac_handle * h)237 conn_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 */
311 static void
crypt_msg(struct tac_handle * h,struct tac_msg * msg)312 crypt_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 */
359 static void *
dup_str(struct tac_handle * h,const struct tac_str * ss,size_t * len)360 dup_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
374 static int
establish_connection(struct tac_handle * h)375 establish_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 */
406 static void
free_str(struct tac_str * cs)407 free_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
417 static void
generr(struct tac_handle * h,const char * format,...)418 generr(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
427 static void
gen_session_id(struct tac_msg * msg)428 gen_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 */
444 static int
get_srvr_end(struct tac_handle * h)445 get_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
460 static int
get_str(struct tac_handle * h,const char * field,struct tac_str * ss,size_t len)461 get_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
476 static void
init_str(struct tac_str * cs)477 init_str(struct tac_str *cs)
478 {
479 cs->data = NULL;
480 cs->len = 0;
481 }
482
483 static int
read_timed(struct tac_handle * h,void * buf,size_t len,const struct timeval * deadline)484 read_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 */
540 static int
recv_msg(struct tac_handle * h)541 recv_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
594 static int
save_str(struct tac_handle * h,struct tac_str * cs,const void * data,size_t len)595 save_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 */
612 static int
send_msg(struct tac_handle * h)613 send_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
685 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)686 tac_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;
739 fail:
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
751 int
tac_add_server(struct tac_handle * h,const char * host,int port,const char * secret,int timeout,int flags)752 tac_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
760 void
tac_close(struct tac_handle * h)761 tac_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
785 static void
freev(char ** fields,int nfields)786 freev(char **fields, int nfields)
787 {
788 if (fields != NULL) {
789 while (nfields-- > 0)
790 free(fields[nfields]);
791 free(fields);
792 }
793 }
794
795 int
tac_config(struct tac_handle * h,const char * path)796 tac_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
887 int
tac_create_authen(struct tac_handle * h,int action,int type,int service)888 tac_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
903 int
tac_create_author(struct tac_handle * h,int method,int type,int service)904 tac_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
919 int
tac_create_acct(struct tac_handle * h,int acct,int action,int type,int service)920 tac_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
936 static void
create_msg(struct tac_handle * h,int msg_type,int var,int type)937 create_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
959 void *
tac_get_data(struct tac_handle * h,size_t * len)960 tac_get_data(struct tac_handle *h, size_t *len)
961 {
962 return dup_str(h, &h->srvr_data, len);
963 }
964
965 char *
tac_get_msg(struct tac_handle * h)966 tac_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 */
976 struct tac_handle *
tac_open(void)977 tac_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
1003 int
tac_send_authen(struct tac_handle * h)1004 tac_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
1055 int
tac_send_author(struct tac_handle * h)1056 tac_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
1128 int
tac_send_acct(struct tac_handle * h)1129 tac_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
1171 int
tac_set_rem_addr(struct tac_handle * h,const char * addr)1172 tac_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
1177 int
tac_set_data(struct tac_handle * h,const void * data,size_t data_len)1178 tac_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
1183 int
tac_set_msg(struct tac_handle * h,const char * msg)1184 tac_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
1189 int
tac_set_port(struct tac_handle * h,const char * port)1190 tac_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
1195 int
tac_set_priv(struct tac_handle * h,int priv)1196 tac_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
1206 int
tac_set_user(struct tac_handle * h,const char * user)1207 tac_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
1212 int
tac_set_av(struct tac_handle * h,u_int index,const char * av)1213 tac_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
1220 char *
tac_get_av(struct tac_handle * h,u_int index)1221 tac_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
1234 char *
tac_get_av_value(struct tac_handle * h,const char * attribute)1235 tac_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
1293 void
tac_clear_avs(struct tac_handle * h)1294 tac_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
1301 static void
clear_srvr_avs(struct tac_handle * h)1302 clear_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
1312 const char *
tac_strerror(struct tac_handle * h)1313 tac_strerror(struct tac_handle *h)
1314 {
1315 return h->errmsg;
1316 }
1317
1318 static void *
xmalloc(struct tac_handle * h,size_t size)1319 xmalloc(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
1328 static char *
xstrdup(struct tac_handle * h,const char * s)1329 xstrdup(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