Example #1
0
/* 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, but actually the aren't. Attributes are
   discarded. 
*/
void tac_author_read(int fd, struct areply *re) {
	HDR th;
	struct author_reply *tb;
	int len_from_header, r, len_from_body;
	char *pktp;
	char *msg = NULL;

	bzero(re, sizeof(struct areply));
	
	r=read(fd, &th, TAC_PLUS_HDR_SIZE);
	if(r < TAC_PLUS_HDR_SIZE) {
  		syslog(LOG_ERR,
 			"%s: short author header, %d of %d: %m", __FUNCTION__,
		 	r, TAC_PLUS_HDR_SIZE);
		re->msg = system_err_msg;
		re->status = AUTHOR_STATUS_ERROR;
		goto AuthorExit;
 	}

	/* 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 = msg;
		re->status = AUTHOR_STATUS_ERROR;
		goto AuthorExit;
	}

 	len_from_header=ntohl(th.datalength);
 	tb=(struct author_reply *) xcalloc(1, len_from_header);

 	/* read reply packet body */
 	r=read(fd, tb, len_from_header);
 	if(r < len_from_header) {
  		syslog(LOG_ERR,
			 "%s: short author body, %d of %d: %m", __FUNCTION__,
			 r, len_from_header);
		re->msg = system_err_msg;
		re->status = AUTHOR_STATUS_ERROR;
		goto AuthorExit;
 	}

 	/* decrypt the body */
 	_tac_crypt((u_char *) tb, &th, len_from_header);

 	/* 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;
	
	for(r = 0; r < tb->arg_cnt; r++) {
	    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) {
  		syslog(LOG_ERR,
			"%s: inconsistent author reply body, incorrect key?",
			__FUNCTION__);
		re->msg = system_err_msg;
		re->status = AUTHOR_STATUS_ERROR;
		goto AuthorExit;
 	}

	/* packet seems to be consistent, prepare return messages */
	/* server message for user */
	if(tb->msg_len) {
		char *msg = (char *) 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);
		re->msg = msg;
	}

	/* server message to syslog */
	if(tb->data_len) {
		char *smsg=(char *) 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);
		syslog(LOG_ERR, "%s: author failed: %s", __FUNCTION__,smsg);
		free(smsg);
	}

	/* prepare status */
	switch(tb->status) {
		/* success conditions */
		/* XXX support optional vs mandatory arguments */
		case AUTHOR_STATUS_PASS_ADD:
		case AUTHOR_STATUS_PASS_REPL:
			{
				char *argp; 

				if(!re->msg) re->msg=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;
				/* argp points to current argument string
				   pktp holds current argument length */
				for(r=0; r < tb->arg_cnt; r++) {
					char buff[256];
					char name[128];
					char content[128];
					char *sep;
					char *attrib;
					char *value;
					
					bcopy(argp, buff, *pktp);
					buff[*pktp] = '\0';
					sep=index(buff, '=');
					if(sep == NULL)
							index(buff, '*');
					if(sep == NULL)
							syslog(LOG_WARNING, "%s: attribute contains no separator: %s", buff);
					*sep = '\0';
					value = ++sep;
					/* now buff points to attribute name,
					   value to the attribute value */
					tac_add_attrib(&re->attr, buff, value);
					
					argp += *pktp;
					pktp++; 
				}
			}
			
			break;

		/* authorization failure conditions */
		/* failing to follow is allowed by RFC, page 23  */
		case AUTHOR_STATUS_FOLLOW: 
		case AUTHOR_STATUS_FAIL:
			if(!re->msg) re->msg=author_fail_msg;
			re->status=AUTHOR_STATUS_FAIL;
			break;

		/* error conditions */	
		case AUTHOR_STATUS_ERROR:
		default:
			if(!re->msg) re->msg=author_err_msg;
			re->status=AUTHOR_STATUS_ERROR;
	}

AuthorExit:

	free(tb);	
	TACDEBUG((LOG_DEBUG, "%s: server replied '%s'", __FUNCTION__, \
			re->msg))
	
}
Example #2
0
const char *tac_account_read(int fd) {
	HDR th;
	struct acct_reply *tb;
	int len_from_header, r, len_from_body;
	const char *msg = NULL;
    char * msg_tmp = NULL;

	r=read(fd, &th, TAC_PLUS_HDR_SIZE);
	if(r < TAC_PLUS_HDR_SIZE) {
  		DEBUG_TACPLUS("short acct header, %d of %d", r, TAC_PLUS_HDR_SIZE);
  		return(system_err_msg);
 	}

 	/* check the reply fields in header */
	msg = _tac_check_header(&th, TAC_PLUS_ACCT);
    
	if(msg != NULL) 
	return(msg);

 	len_from_header=ntohl(th.datalength);
 	tb=(struct acct_reply *) xcalloc(1, len_from_header);    
 	/* read reply packet body */
 	r=read(fd, tb, len_from_header); 	
 	if(r < len_from_header) {
  		DEBUG_TACPLUS("incomplete message body, %d bytes, expected %d", r, len_from_header);
  		return(system_err_msg);
 	}
 	/* 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 the length fields */
 	len_from_body=sizeof(tb->msg_len) + sizeof(tb->data_len) +
            sizeof(tb->status) + tb->msg_len + tb->data_len;

 	if(len_from_header != len_from_body) {
  		DEBUG_TACPLUS("invalid reply content, incorrect key?");
  		return(system_err_msg);
 	}

 	/* save status and clean up */
 	r=tb->status;
	if(tb->msg_len) {
		msg_tmp = (char *) xcalloc(1, tb->msg_len);
		bcopy((u_char *) tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE, msg_tmp, tb->msg_len);
        msg = msg_tmp;
	} else
		msg="Accounting failed";

 	free(tb);

 	/* server logged our request successfully */
	if(r == TAC_PLUS_ACCT_STATUS_SUCCESS) {
		DEBUG_TACPLUS("accounted ok");
		msg=NULL;
		return(NULL);
	}
	/* return pointer to server message */
	DEBUG_TACPLUS("accounting failed, server reply was %d (%s)", r, msg);
 	return(msg);

}
int
tac_account_read(tacacs_conf_t *conf, tacacs_server_t *server,
		 const char **ret_err_msg)
{
        int err = 0;
	HDR th;
	struct acct_reply *tb = NULL;
	int len_from_header, r, len_from_body;
	const char *msg = NULL;
	int msg_len, data_len;

	if (ret_err_msg == NULL) {
	    syslog(LOG_ERR, "%s: error no err msg buffer provided",
		   __FUNCTION__);
	    err = -1;
	    goto bail;
	}
	*ret_err_msg = NULL;

	if (server == NULL) {
	    syslog(LOG_ERR, "%s: error no TACACS+ server specified",
		   __FUNCTION__);
	    err = -1;
	    *ret_err_msg = no_server_err_msg;
	    goto bail;
	}

	reset_server(server, FALSE);

	r=read(conf->sockfd, &th, TAC_PLUS_HDR_SIZE);
	if(r < TAC_PLUS_HDR_SIZE) {
  		syslog(LOG_ERR,
 			"%s: short acct header, %d of %d: %m", __FUNCTION__,
		 	r, TAC_PLUS_HDR_SIZE);
		err = -1;
		*ret_err_msg = r == 0 ? "No response from server" :
                                        "Truncated response from server";
		goto bail;
 	}

 	/* check the reply fields in header */
	err = _tac_check_header(&th, TAC_PLUS_ACCT, server, &msg);
	if (err) {
            *ret_err_msg = msg;
	    goto bail;
	}

 	len_from_header=ntohl(th.datalength);
 	tb=(struct acct_reply *) xcalloc(1, len_from_header);

 	/* read reply packet body */
 	r=read(conf->sockfd, tb, len_from_header);
 	if(r < len_from_header) {
  		syslog(LOG_ERR,
			 "%s: incomplete message body, %d bytes, expected %d: %m",
			 __FUNCTION__,
			 r, len_from_header);
		err = -1;
		*ret_err_msg = r == 0 ? "Empty response message from server" :
                                        "Incomplete response message from server";
		goto bail;
 	}

 	/* decrypt the body */
 	_tac_crypt(server->secret, (u_char *) tb, &th, len_from_header);

	msg_len = tb->msg_len;
	data_len = tb->data_len;

 	/* check the length fields */
 	len_from_body=sizeof(tb->msg_len) + sizeof(tb->data_len) +
            sizeof(tb->status) + msg_len + data_len;

 	if(len_from_header != len_from_body) {
  		syslog(LOG_ERR,
			"%s: invalid reply content, incorrect key?",
			__FUNCTION__);
		err = -1;
		*ret_err_msg = system_err_msg;
		goto bail;
 	}

 	/* save status and clean up */
 	r=tb->status;
	if(msg_len) {
	    server->server_msg=(char *) xcalloc(1, msg_len);
	    bcopy(tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE, server->server_msg,
		  msg_len); 
	    *ret_err_msg = server->server_msg;
	}

 	/* server logged our request successfully */
	if(r == TAC_PLUS_ACCT_STATUS_SUCCESS) {
	    TACDEBUG((LOG_DEBUG, "%s: accounted ok", __FUNCTION__));
	    *ret_err_msg = NULL;
	}
	else {
	    /* return pointer to server message */
	    syslog(LOG_ERR, "%s: accounting failed, server reply was %d "
		   "(%s)", __FUNCTION__, r, server->server_msg);
	    if (*ret_err_msg == NULL) {
		*ret_err_msg = "Accounting failed";
	    }
	    err = -1;
	    goto bail;
	}

 bail:
	if (tb) {
	    free(tb);
	}
	return(err);
}
/*
 * reads packet from TACACS+ server; returns: NULL if the authentication
 * succeded string pointer if it failed 
 */
int
tac_authen_read(tacacs_conf_t *conf, tacacs_server_t *server, 
		const char **ret_err_msg, int *ret_status)
{
    HDR th;
    struct authen_reply *tb = NULL;
    int len_from_header, r, len_from_body;
    int serv_msg_len, data_len;
    char *msg = NULL;
    int err = 0;

    if (ret_status) {
        *ret_status = TAC_PLUS_AUTHEN_STATUS_ERROR;
    }
    if (ret_err_msg == NULL) {
	syslog(LOG_ERR, "%s: error no err msg buffer provided",
	       __FUNCTION__);
	err = -1;
	goto bail;
    }
    *ret_err_msg = NULL;

    if (server == NULL) {
	syslog(LOG_ERR, "%s: error no TACACS+ server specified",
	       __FUNCTION__);
	err = -1;
	*ret_err_msg = no_server_err_msg;
	goto bail;
    }

    /* Free from any previous server messages */
    reset_server(server, FALSE);

    /*
     * read the reply header 
     * XXX it would appear that the reads are being done on non-blocking
     * sockets. This should be fixed to deal with partial reads.
     */
    r = read(conf->sockfd, &th, TAC_PLUS_HDR_SIZE);
    if (r < TAC_PLUS_HDR_SIZE) {
	syslog(LOG_ERR,
	       "%s: error reading authen header, read %d of %d: %m",
	       __FUNCTION__, r, TAC_PLUS_HDR_SIZE);
	*ret_err_msg = system_err_msg;
	err = -1;
	goto bail;
    }

    /* check the reply fields in header */
    err = _tac_check_header(&th, TAC_PLUS_AUTHEN, server, ret_err_msg);
    if (err) {
	goto bail;
    }

    len_from_header = ntohl(th.datalength);
    tb = (struct authen_reply *) xcalloc(1, len_from_header);

    /* read reply packet body */
    r = read(conf->sockfd, tb, len_from_header);
    if (r < len_from_header) {
	syslog(LOG_ERR,
	       "%s: incomplete message body, %d bytes, expected %d: %m",
	       __FUNCTION__, r, len_from_header);
	*ret_err_msg = system_err_msg;
	err = -1;
	goto bail;
    }

    /* decrypt the body */
    _tac_crypt(server->secret, (u_char *) tb, &th, len_from_header);

    serv_msg_len = ntohs(tb->msg_len);
    data_len = ntohs(tb->data_len);

    /* check the length fields */
    len_from_body = sizeof(tb->status) + sizeof(tb->flags) +
	sizeof(tb->msg_len) + sizeof(tb->data_len) +
	serv_msg_len + data_len;

    if (len_from_header != len_from_body) {
	syslog(LOG_ERR,
	       "%s: invalid reply content, incorrect key? (calc %d, hdr %d)",
	       __FUNCTION__, len_from_body, len_from_header);
	*ret_err_msg = system_err_msg;
	err = -1;
	goto bail;
    }

    /* Save off any message or data returned by the server */
    if (serv_msg_len) {
	server->server_msg = (char *) xcalloc(1, serv_msg_len);
	bcopy(tb + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE, server->server_msg,
	      serv_msg_len);
	/* Show user what the server said */
	*ret_err_msg = server->server_msg;
    }
    if (data_len) {
	server->data = (char *) xcalloc(1, data_len);
	bcopy(tb + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + serv_msg_len,
	      server->data, data_len);
    }

    /* save status and clean up */
    r = tb->status;
    if (ret_status) {
	*ret_status = r;
    }

    switch (r) {
    case TAC_PLUS_AUTHEN_STATUS_PASS:
	/* server authenticated username and password successfully */
	break;

    case TAC_PLUS_AUTHEN_STATUS_FAIL:
	if (*ret_err_msg == NULL) {
	    *ret_err_msg = auth_fail_msg;
	}
	err = -1;
	break;

    case TAC_PLUS_AUTHEN_STATUS_GETDATA:
    case TAC_PLUS_AUTHEN_STATUS_GETUSER:
    case TAC_PLUS_AUTHEN_STATUS_GETPASS:
	break;

    case TAC_PLUS_AUTHEN_STATUS_ERROR:
	syslog(LOG_ERR,
	       "%s: TACACS+ authentication failed, server detected error",
	   __FUNCTION__);
	err = -1;
	break;

    case TAC_PLUS_AUTHEN_STATUS_RESTART:
    case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
    default:
	syslog(LOG_ERR,
	       "%s: TACACS+ authentication failed, unexpected status %#x",
	   __FUNCTION__, r);
	if (*ret_err_msg == NULL) {
	    *ret_err_msg = unexpected_status_msg;
	}
	err = -1;
	break;
    }

 bail:
    if (err && (*ret_err_msg == NULL)) {
	/* At least say something bad */
	*ret_err_msg = bad_login_msg;
    }
    if (tb) {
	free(tb);
	tb = NULL;
    }
    return(err);
}