summaryrefslogtreecommitdiff
path: root/libtac/lib/author_r.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtac/lib/author_r.c')
-rw-r--r--libtac/lib/author_r.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/libtac/lib/author_r.c b/libtac/lib/author_r.c
new file mode 100644
index 0000000..ba73056
--- /dev/null
+++ b/libtac/lib/author_r.c
@@ -0,0 +1,283 @@
+/* author_r.c - Reads authorization reply from the server.
+ *
+ * Copyright (C) 2010, Pawel Krawczyk <pawel.krawczyk@hush.com> and
+ * Jeroen Nijhof <jeroen@jeroennijhof.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ *
+ * See `CHANGES' file for revision history.
+ */
+
+#include "xalloc.h"
+#include "libtac.h"
+#include "messages.h"
+
+/* This function returns structure containing
+ 1. status (granted/denied)
+ 2. message for the user
+ 3. list of attributes returned by server
+ The attributes should be applied to service authorization
+ is requested for.
+ *
+ * return value:
+ * < 0 : error status code, see LIBTAC_STATUS_...
+ * LIBTAC_STATUS_READ_TIMEOUT
+ * LIBTAC_STATUS_SHORT_HDR
+ * LIBTAC_STATUS_SHORT_BODY
+ * LIBTAC_STATUS_PROTOCOL_ERR
+ * >= 0 : server response, see TAC_PLUS_AUTHOR_STATUS_...
+ */
+int tac_author_read(int fd, struct areply *re) {
+ HDR th;
+ struct author_reply *tb = NULL;
+ unsigned int len_from_header, len_from_body;
+ int r;
+ ssize_t packet_read;
+ u_char *pktp = NULL;
+ char *msg = NULL;
+ int timeleft;
+ re->msg = NULL;
+
+ bzero(re, sizeof(struct areply));
+ if (tac_readtimeout_enable &&
+ tac_read_wait(fd,tac_timeout*1000,TAC_PLUS_HDR_SIZE,&timeleft) < 0 ) {
+ if (timeleft > 0) {
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply error, connection closed", __func__))
+ re->status = LIBTAC_STATUS_CONN_CLOSED;
+ }
+ else {
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply timeout after %d secs", __func__, tac_timeout))
+ re->status = LIBTAC_STATUS_READ_TIMEOUT;
+ }
+ re->msg = tac_xstrdup(author_syserr_msg);
+ free(tb);
+ return re->status;
+ }
+
+ packet_read = read(fd, &th, TAC_PLUS_HDR_SIZE);
+ if(packet_read < TAC_PLUS_HDR_SIZE) {
+ if (packet_read < 0)
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply header read error: %m", __func__))
+ else
+ TACSYSLOG((LOG_ERR,\
+ "%s: short reply header, read %ld of %d", __func__,\
+ packet_read, TAC_PLUS_HDR_SIZE))
+ re->msg = tac_xstrdup(author_syserr_msg);
+ re->status = LIBTAC_STATUS_SHORT_HDR;
+ free(tb);
+ return re->status;
+ }
+
+ /* check header consistency */
+ msg = _tac_check_header(&th, TAC_PLUS_AUTHOR);
+ if (msg != NULL) {
+ /* no need to process body if header is broken */
+ re->msg = tac_xstrdup(msg);
+ re->status = LIBTAC_STATUS_PROTOCOL_ERR;
+ free(tb);
+ return re->status;
+ }
+
+ len_from_header = ntohl(th.datalength);
+ if (len_from_header > TAC_PLUS_MAX_PACKET_SIZE) {
+ TACSYSLOG((LOG_ERR,\
+ "%s: length declared in the packet %d exceeds max packet size %d",\
+ __func__,\
+ len_from_header, TAC_PLUS_MAX_PACKET_SIZE))
+ re->status = LIBTAC_STATUS_PROTOCOL_ERR;
+ free(tb);
+ return re->status;
+ }
+ tb = (struct author_reply *) tac_xcalloc(1, len_from_header);
+
+ /* read reply packet body */
+ if (tac_readtimeout_enable &&
+ tac_read_wait(fd,timeleft,len_from_header,&timeleft) < 0 ) {
+ if (timeleft > 0) {
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply error, connection closed", __func__))
+ re->status = LIBTAC_STATUS_CONN_CLOSED;
+ }
+ else {
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply timeout after %d secs", __func__, tac_timeout))
+ re->status = LIBTAC_STATUS_READ_TIMEOUT;
+ }
+ re->msg = tac_xstrdup(author_syserr_msg);
+ free(tb);
+ return re->status;
+ }
+ packet_read = read(fd, tb, len_from_header);
+ if (packet_read < len_from_header) {
+ if (packet_read < 0)
+ TACSYSLOG((LOG_ERR,\
+ "%s: reply body read error: %m", __func__))
+ else
+ TACSYSLOG((LOG_ERR,\
+ "%s: short reply body, read %ld of %d", __func__,\
+ packet_read, len_from_header))
+ re->msg = tac_xstrdup(author_syserr_msg);
+ re->status = LIBTAC_STATUS_SHORT_BODY;
+ free(tb);
+ return re->status;
+ }
+
+ /* decrypt the body */
+ _tac_crypt((u_char *) tb, &th, len_from_header);
+
+ /* Convert network byte order to host byte order */
+ tb->msg_len = ntohs(tb->msg_len);
+ tb->data_len = ntohs(tb->data_len);
+
+ /* check consistency of the reply body
+ * len_from_header = declared in header
+ * len_from_body = value computed from body fields
+ */
+ len_from_body = TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE +
+ tb->msg_len + tb->data_len;
+
+ pktp = (u_char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;
+
+ /* cycle through the arguments supplied in the packet */
+ for (r = 0; r < tb->arg_cnt; r++) {
+ if (len_from_body > packet_read || ((void *)pktp - (void *) tb) > packet_read) {
+ TACSYSLOG((LOG_ERR,\
+ "%s: arguments supplied in packet seem to exceed its size",\
+ __func__))
+ re->msg = tac_xstrdup(protocol_err_msg);
+ re->status = LIBTAC_STATUS_PROTOCOL_ERR;
+ free(tb);
+ return re->status;
+ }
+ len_from_body += sizeof(u_char); /* add arg length field's size*/
+ len_from_body += *pktp; /* add arg length itself */
+ pktp++;
+ }
+
+ if(len_from_header != len_from_body) {
+ TACSYSLOG((LOG_ERR,\
+ "%s: inconsistent reply body, incorrect key?",\
+ __func__))
+ re->msg = tac_xstrdup(protocol_err_msg);
+ re->status = LIBTAC_STATUS_PROTOCOL_ERR;
+ free(tb);
+ return re->status;
+ }
+
+ /* packet seems to be consistent, prepare return messages */
+ /* server message for user */
+ if(tb->msg_len) {
+ char *msg = (char *) tac_xcalloc(1, tb->msg_len+1);
+ bcopy((u_char *) tb+TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE
+ + (tb->arg_cnt)*sizeof(u_char),
+ msg, tb->msg_len);
+ msg[(int) tb->msg_len] = '\0';
+ re->msg = msg; /* freed by caller */
+ }
+
+ /* server message to syslog */
+ if(tb->data_len) {
+ char *smsg=(char *) tac_xcalloc(1, tb->data_len+1);
+ bcopy((u_char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE
+ + (tb->arg_cnt)*sizeof(u_char)
+ + tb->msg_len, smsg,
+ tb->data_len);
+ smsg[(int) tb->data_len] = '\0';
+ TACSYSLOG((LOG_ERR, "%s: reply message: %s", __func__,smsg))
+ free(smsg);
+ }
+
+ TACDEBUG((LOG_DEBUG, "%s: authorization reply status=%d",\
+ __func__, tb->status));
+
+ /* prepare status */
+ switch(tb->status) {
+ /* success conditions */
+ /* XXX support optional vs mandatory arguments */
+ case TAC_PLUS_AUTHOR_STATUS_PASS_REPL:
+ tac_free_attrib(&re->attr);
+
+ case TAC_PLUS_AUTHOR_STATUS_PASS_ADD:
+ {
+ u_char *argp;
+
+ if(!re->msg) re->msg=tac_xstrdup(author_ok_msg);
+ re->status=tb->status;
+
+ /* add attributes received to attribute list returned to
+ the client */
+ pktp = (u_char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;
+ argp = pktp + (tb->arg_cnt * sizeof(u_char)) + tb->msg_len +
+ tb->data_len;
+ TACDEBUG((LOG_DEBUG, "Args cnt %d", tb->arg_cnt));
+ /* argp points to current argument string
+ pktp points to current argument length */
+ for(r=0; r < tb->arg_cnt; r++) {
+ char buff[256];
+ char *sep;
+ char *value;
+ char sepchar = '=';
+
+ bcopy(argp, buff, (int)*pktp);
+ buff[(int)*pktp] = '\0';
+ sep = strchr(buff, '=');
+ if ( sep == NULL ) {
+ sep = strchr(buff, '*');
+ }
+ if(sep == NULL) {
+ TACSYSLOG((LOG_WARNING,\
+ "AUTHOR_STATUS_PASS_ADD/REPL: av pair does not contain a separator: %s",\
+ buff))
+ /* now buff points to attribute name, make value ""
+ treat as "name=" */
+ value = "";
+ } else {
+ sepchar = *sep;
+ *sep = '\0';
+ value = ++sep;
+ /* now buff points to attribute name,
+ value to the attribute value */
+ }
+ TACDEBUG((LOG_DEBUG, "Adding buf/value pair (%s,%s)", buff, value));
+ tac_add_attrib_pair(&re->attr, buff, sepchar, value);
+ argp += *pktp;
+ pktp++;
+ }
+ }
+ free(tb);
+ return re->status;
+ break;
+ }
+
+ switch (tb->status) {
+ /* authorization failure conditions */
+ /* failing to follow is allowed by RFC, page 23 */
+ case TAC_PLUS_AUTHOR_STATUS_FOLLOW:
+ case TAC_PLUS_AUTHOR_STATUS_FAIL:
+ if(!re->msg) re->msg = tac_xstrdup(author_fail_msg);
+ re->status=TAC_PLUS_AUTHOR_STATUS_FAIL;
+ break;
+ /* error conditions */
+ case TAC_PLUS_AUTHOR_STATUS_ERROR:
+ default:
+ if(!re->msg) re->msg = tac_xstrdup(author_err_msg);
+ re->status=TAC_PLUS_AUTHOR_STATUS_ERROR;
+ }
+
+ free(tb);
+ return re->status;
+}