Beispiel #1
0
/* this function sends a packet do TACACS+ server, asking
 * for validation of given username and password
 *
 * return value:
 *      0 : success
 *   <  0 : error status code, see LIBTAC_STATUS_...
 *             LIBTAC_STATUS_WRITE_ERR
 *             LIBTAC_STATUS_WRITE_TIMEOUT
 *             LIBTAC_STATUS_ASSEMBLY_ERR
 */
int tac_authen_send(int fd, const char *user, const char *pass, const char *tty,
		const char *r_addr, u_char action) {

	HDR *th; /* TACACS+ packet header */
	struct authen_start tb; /* message body */
	int user_len, pass_len, port_len, chal_len, token_len, bodylength, w;
	int r_addr_len;
	int pkt_len = 0;
	int ret = 0;
	char *chal = "1234123412341234";
	char *token = NULL;
	u_char *pkt = NULL;
	const uint8_t id = 5;

	th = _tac_req_header(TAC_PLUS_AUTHEN, 0);

	/* set some header options */
	if (!strcmp(tac_login, "login")) {
		th->version = TAC_PLUS_VER_0;
	} else {
		th->version = TAC_PLUS_VER_1;
	}
	th->encryption =
			tac_encryption ?
					TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG;

	TACDEBUG(LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s",
					__FUNCTION__, user, tty, r_addr,
					(tac_encryption) ? "yes" : "no");

	/* get size of submitted data */
	user_len = strlen(user);
	chal_len = strlen(chal);
	pass_len = strlen(pass);
	port_len = strlen(tty);
	r_addr_len = strlen(r_addr);

	if (!strcmp(tac_login, "chap")) {
		u_char digest[MD5_LBLOCK];

		digest_chap(digest, id, pass, pass_len, chal, chal_len);

		token_len = sizeof(id) + chal_len + sizeof(digest);
		token = xcalloc(1, token_len);
		token[0] = id;
		memcpy(token + sizeof(id), chal, chal_len);
		memcpy(token + sizeof(id) + chal_len, digest, sizeof(digest));
	} else {
		token = xstrdup(pass);
		token_len = strlen(token);
	}

	/* fill the body of message */
	tb.action = action;
	tb.priv_lvl = tac_priv_lvl;
	if (!*tac_login) {
		/* default to PAP */
		tb.authen_type =
				TAC_PLUS_AUTHEN_CHPASS == action ?
						TAC_PLUS_AUTHEN_TYPE_ASCII : TAC_PLUS_AUTHEN_TYPE_PAP;
	} else {
		if (!strcmp(tac_login, "chap")) {
			tb.authen_type = TAC_PLUS_AUTHEN_TYPE_CHAP;
		} else if (!strcmp(tac_login, "login")) {
			tb.authen_type = TAC_PLUS_AUTHEN_TYPE_ASCII;
		} else {
			tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
		}
	}
	tb.service = tac_authen_service;
	tb.user_len = user_len;
	tb.port_len = port_len;
	tb.r_addr_len = r_addr_len; /* may be e.g Caller-ID in future */
	tb.data_len = token_len;

	/* fill body length in header */
	bodylength = sizeof(tb) + user_len + port_len + r_addr_len + token_len;

	th->datalength = htonl(bodylength);

	/* we can now write the header */
	w = write(fd, th, TAC_PLUS_HDR_SIZE);
	if (w < 0 || w < TAC_PLUS_HDR_SIZE) {
		TACSYSLOG(
				LOG_ERR, "%s: short write on header, wrote %d of %d: %m", __FUNCTION__, w, TAC_PLUS_HDR_SIZE);
		free(token);
		free(pkt);
		free(th);
		return LIBTAC_STATUS_WRITE_ERR;
	}

	/* build the packet */
	pkt = (u_char *) xcalloc(1, bodylength + 10);

	bcopy(&tb, pkt + pkt_len, sizeof(tb)); /* packet body beginning */
	pkt_len += sizeof(tb);
	bcopy(user, pkt + pkt_len, user_len); /* user */
	pkt_len += user_len;
	bcopy(tty, pkt + pkt_len, port_len); /* tty */
	pkt_len += port_len;
	bcopy(r_addr, pkt + pkt_len, r_addr_len); /* rem addr */
	pkt_len += r_addr_len;

	bcopy(token, pkt + pkt_len, token_len); /* password */
	pkt_len += token_len;

	/* pkt_len == bodylength ? */
	if (pkt_len != bodylength) {
		TACSYSLOG(
				LOG_ERR, "%s: bodylength %d != pkt_len %d", __FUNCTION__, bodylength, pkt_len);
		free(token);
		free(pkt);
		free(th);
		return LIBTAC_STATUS_ASSEMBLY_ERR;
	}

	/* encrypt the body */
	_tac_crypt(pkt, th);

	w = write(fd, pkt, pkt_len);
	if (w < 0 || w < pkt_len) {
		TACSYSLOG(
				LOG_ERR, "%s: short write on body, wrote %d of %d: %m", __FUNCTION__, w, pkt_len);
		ret = LIBTAC_STATUS_WRITE_ERR;
	}

	free(token);
	free(pkt);
	free(th);
	TACDEBUG(LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret);
	return ret;
} /* tac_authen_send */
Beispiel #2
0
/* Send authorization request to the server, along with attributes
   specified in attribute list prepared with tac_add_attrib.
*/
int tac_author_send(int fd, const char *user, const char *tty, struct tac_attrib *attr) {
	HDR *th;
	struct author tb;
	u_char user_len, port_len;
	struct tac_attrib *a;
	int i = 0; 			/* attributes count */
	int pkt_len = 0; 	/* current packet length */
	int pktl = 0;		/* temporary storage for previous pkt_len values */
	int w; 				/* write() return value */
	u_char *pkt;		/* packet building pointer */
	/* u_char *pktp; */		/* obsolete */
	int ret = 0;
    
	th=_tac_req_header(TAC_PLUS_AUTHOR);

	/* set header options */
 	th->version=TAC_PLUS_VER_0;
 	th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;

	DEBUG_TACPLUS("user '%s', tty '%s', encrypt: %s", user, tty, tac_encryption ? "yes" : "no");
	
	user_len=(u_char) strlen(user);
	port_len=(u_char) strlen(tty);

	tb.authen_method=AUTHEN_METH_TACACSPLUS;
	tb.priv_lvl=TAC_PLUS_PRIV_LVL_MIN;
	if(strcmp(tac_login,"chap") == 0) {
		tb.authen_type=TAC_PLUS_AUTHEN_TYPE_CHAP;
	} else if(strcmp(tac_login,"login") == 0) {
		tb.authen_type=TAC_PLUS_AUTHEN_TYPE_ASCII;
	} else {
		tb.authen_type=TAC_PLUS_AUTHEN_TYPE_PAP;
	}
	tb.service=TAC_PLUS_AUTHEN_SVC_PPP;
	tb.user_len=user_len;
	tb.port_len=port_len;
	tb.rem_addr_len=0;

	/* allocate packet */
	pkt=(u_char *) xcalloc(1, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE);
	pkt_len=sizeof(tb);

	/* fill attribute length fields */
	a = attr;
	while(a) {
		
		pktl = pkt_len;
		pkt_len += sizeof(a->attr_len);
		pkt = xrealloc(pkt, pkt_len);
		bcopy(&a->attr_len, pkt + pktl, sizeof(a->attr_len));
		i++;

		a = a->next;
	}

	/* fill the arg count field and add the fixed fields to packet */
	tb.arg_cnt = i;
	bcopy(&tb, pkt, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE);

	/* fill user and port fields */
	PUTATTR(user, user_len)
	PUTATTR(tty, port_len)

	/* fill attributes */
	a = attr;
	while(a) {
		PUTATTR(a->attr, a->attr_len)

		a = a->next;
	}

	/* finished building packet, fill len_from_header in header */
	th->datalength = htonl(pkt_len);

	/* write header */
 	w=write(fd, th, TAC_PLUS_HDR_SIZE);

	if(w < TAC_PLUS_HDR_SIZE) {
		DEBUG_TACPLUS("author hdr send failed: wrote %d of %d", w, TAC_PLUS_HDR_SIZE);
		ret = -1;
	}
	
	/* encrypt packet body  */
 	_tac_crypt(pkt, th, pkt_len);

	/* write body */
	w=write(fd, pkt, pkt_len);
	if(w < pkt_len) {
		DEBUG_TACPLUS("author body send failed: wrote %d of %d", w, pkt_len);
		ret = -1;
	}

	free(pkt);
	free(th);

	return(ret);
}
Beispiel #3
0
/*
 * return value:
 *      0 : success
 *   <  0 : error status code, see LIBTAC_STATUS_...
 *             LIBTAC_STATUS_WRITE_ERR
 *             LIBTAC_STATUS_WRITE_TIMEOUT  (pending impl)
 *             LIBTAC_STATUS_ASSEMBLY_ERR   (pending impl)
 */
int tac_acct_send(int fd, int type, const char *user, char *tty,
    char *r_addr, struct tac_attrib *attr) {

    HDR *th;
    struct acct tb;
    u_char user_len, port_len, r_addr_len;
    struct tac_attrib *a;
    int i = 0;    /* arg count */
    int pkt_len = 0;
    int pktl = 0;
    int w;    /* write count */
    u_char *pkt=NULL;
    /* u_char *pktp; */             /* obsolute */
    int ret = 0;

    th = _tac_req_header(TAC_PLUS_ACCT, 0);

    /* set header options */
    th->version=TAC_PLUS_VER_0;
    th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG;

    TACDEBUG(LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s, type: %s", \
        __FUNCTION__, user, tty, r_addr, \
        (tac_encryption) ? "yes" : "no", \
        tac_acct_flag2str(type));
        
    user_len=(u_char) strlen(user);
    port_len=(u_char) strlen(tty);
    r_addr_len=(u_char) strlen(r_addr);

    tb.flags=(u_char) type;
    tb.authen_method=tac_authen_method;
    tb.priv_lvl=tac_priv_lvl;
    if (!*tac_login) {
        /* default to PAP */
        tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
    } else {
        if (strcmp(tac_login,"chap") == 0) {
            tb.authen_type=TAC_PLUS_AUTHEN_TYPE_CHAP;
        } else if(strcmp(tac_login,"login") == 0) {
            tb.authen_type=TAC_PLUS_AUTHEN_TYPE_ASCII;
        } else {
            tb.authen_type=TAC_PLUS_AUTHEN_TYPE_PAP;
        }
    }
    tb.authen_service=tac_authen_service;
    tb.user_len=user_len;
    tb.port_len=port_len;
    tb.r_addr_len=r_addr_len;

    /* allocate packet */
    pkt=(u_char *) xcalloc(1, TAC_ACCT_REQ_FIXED_FIELDS_SIZE);
    pkt_len=sizeof(tb);

    /* fill attribute length fields */
    a = attr;
    while (a) {
        pktl = pkt_len;
        pkt_len += sizeof(a->attr_len);
        pkt = (u_char*) xrealloc(pkt, pkt_len);

        /* see comments in author_s.c
        pktp=pkt + pkt_len;
        pkt_len += sizeof(a->attr_len);
        pkt = xrealloc(pkt, pkt_len);   
        */

        bcopy(&a->attr_len, pkt + pktl, sizeof(a->attr_len));
        i++;

        a = a->next;
    }

    /* fill the arg count field and add the fixed fields to packet */
    tb.arg_cnt = i;
    bcopy(&tb, pkt, TAC_ACCT_REQ_FIXED_FIELDS_SIZE);

    /*
#define PUTATTR(data, len) \
        pktp = pkt + pkt_len; \
        pkt_len += len; \
        pkt = xrealloc(pkt, pkt_len); \
        bcopy(data, pktp, len);
    */
#define PUTATTR(data, len) \
    pktl = pkt_len; \
    pkt_len += len; \
    pkt = (u_char*) xrealloc(pkt, pkt_len); \
    bcopy(data, pkt + pktl, len);

    /* fill user and port fields */
    PUTATTR(user, user_len)
    PUTATTR(tty, port_len)
    PUTATTR(r_addr, r_addr_len)

    /* fill attributes */
    a = attr;
    while(a) {
        PUTATTR(a->attr, a->attr_len)
        a = a->next;
    }

    /* finished building packet, fill len_from_header in header */
    th->datalength = htonl(pkt_len);

    /* write header */
    w = write(fd, th, TAC_PLUS_HDR_SIZE);

    if(w < TAC_PLUS_HDR_SIZE) {
        TACSYSLOG(LOG_ERR, "%s: short write on header, wrote %d of %d: %m",\
            __FUNCTION__, w, TAC_PLUS_HDR_SIZE);
        free(pkt);
        free(th);
        return LIBTAC_STATUS_WRITE_ERR;
    }
        
    /* encrypt packet body  */
    _tac_crypt(pkt, th);

    /* write body */
    w=write(fd, pkt, pkt_len);
    if(w < pkt_len) {
        TACSYSLOG(LOG_ERR, "%s: short write on body, wrote %d of %d: %m",\
            __FUNCTION__, w, pkt_len);
        ret = LIBTAC_STATUS_WRITE_ERR;
    }

    free(pkt);
    free(th);
    TACDEBUG(LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret);
    return ret;
}
Beispiel #4
0
/* this function sends a continue packet do TACACS+ server, asking
 * for validation of given password
 *
 * return value:
 *      0 : success
 *   <  0 : error status code, see LIBTAC_STATUS_...
 *         LIBTAC_STATUS_WRITE_ERR
 *         LIBTAC_STATUS_WRITE_TIMEOUT  (pending impl)
 *         LIBTAC_STATUS_ASSEMBLY_ERR
 */
int tac_cont_send(int fd, char *pass) {
    HDR *th;        /* TACACS+ packet header */
    struct authen_cont tb;  /* continue body */
    int pass_len, bodylength, w;
    int pkt_len = 0;
    int ret = 0;
    u_char *pkt = NULL;

    th = _tac_req_header(TAC_PLUS_AUTHEN, 1);

    /* set some header options */
    th->version = TAC_PLUS_VER_0;
    th->seq_no = 3;       /* 1 = request, 2 = reply, 3 = continue, 4 = reply */
    th->encryption = tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG;

    /* get size of submitted data */
    pass_len = strlen(pass);

    /* fill the body of message */
    tb.user_msg_len = htons(pass_len);
    tb.user_data_len = tb.flags = 0;

    /* fill body length in header */
    bodylength = TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE+0+pass_len;

    th->datalength = htonl(bodylength);

    /* we can now write the header */
    w = write(fd, th, TAC_PLUS_HDR_SIZE);
    if (w < 0 || w < TAC_PLUS_HDR_SIZE) {
        TACSYSLOG((LOG_ERR, "%s: short write on header, wrote %d of %d: %m",\
            __FUNCTION__, w, TAC_PLUS_HDR_SIZE))
        free(pkt);
        free(th);
        return LIBTAC_STATUS_WRITE_ERR;
    }

    /* build the packet */
    pkt = (u_char *) tac_xcalloc(1, bodylength);

    bcopy(&tb, pkt+pkt_len, TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE); /* packet body beginning */
    pkt_len += TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
    bcopy(pass, pkt+pkt_len, pass_len);  /* password */
    pkt_len += pass_len;

    /* pkt_len == bodylength ? */
    if (pkt_len != bodylength) {
        TACSYSLOG((LOG_ERR,\
            "%s: bodylength %d != pkt_len %d",\
            __FUNCTION__, bodylength, pkt_len))
        free(pkt);
        free(th);
        return LIBTAC_STATUS_ASSEMBLY_ERR;
    } 
    
    /* encrypt the body */
    _tac_crypt(pkt, th, bodylength);

    w = write(fd, pkt, pkt_len);
    if (w < 0 || w < pkt_len) {
        TACSYSLOG((LOG_ERR,\
            "%s: short write on body, wrote %d of %d: %m",\
            __FUNCTION__, w, pkt_len))
        ret=LIBTAC_STATUS_WRITE_ERR;
    }

    free(pkt);
    free(th);
    TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret))
    return ret;
} /* tac_cont_send */
Beispiel #5
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))
	
}
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);
}
Beispiel #7
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);

}
Beispiel #8
0
/* this function sends a packet do TACACS+ server, asking
 * for validation of given username and password
 *
 * return value:
 *      0 : success
 *   <  0 : error status code, see LIBTAC_STATUS_...
 *             LIBTAC_STATUS_WRITE_ERR
 *             LIBTAC_STATUS_WRITE_TIMEOUT
 *             LIBTAC_STATUS_ASSEMBLY_ERR
 */
int tac_authen_send(int fd, const char *user, char *pass, char *tty,
    char *r_addr, int action, int ctrl) {

    HDR *th;    /* TACACS+ packet header */
    struct authen_start tb;     /* message body */
    int user_len, port_len, chal_len, mdp_len, token_len, bodylength, w;
    int r_addr_len;
    int pkt_len = 0;
    int ret = 0;
    char *chal = "1234123412341234";
    char digest[MD5_LEN];
    char *token = NULL;
    u_char *pkt = NULL, *mdp = NULL;
    MD5_CTX mdcontext;

    th=_tac_req_header(TAC_PLUS_AUTHEN, 0);

    /* set some header options */
    if ((tac_login != NULL) && (strcmp(tac_login,"login") == 0)) {
        th->version = TAC_PLUS_VER_0;
    } else {
        th->version = TAC_PLUS_VER_1;
    }
    th->encryption = tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG;

    if (ctrl & PAM_TAC_DEBUG)
    	TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s", \
			__FUNCTION__, user, tty, r_addr, \
			(tac_encryption) ? "yes" : "no"))
        
    if ((tac_login != NULL) && (strcmp(tac_login,"chap") == 0)) {
        chal_len = strlen(chal);
        mdp_len = sizeof(u_char) + strlen(pass) + chal_len;
        mdp = (u_char *) xcalloc(1, mdp_len);
        mdp[0] = 5;
        memcpy(&mdp[1], pass, strlen(pass));
        memcpy(mdp + strlen(pass) + 1, chal, chal_len);
        MD5Init(&mdcontext);
        MD5Update(&mdcontext, mdp, mdp_len);
        MD5Final((u_char *) digest, &mdcontext);
        free(mdp);
        token = (char*) xcalloc(1, sizeof(u_char) + 1 + chal_len + MD5_LEN);
        token[0] = 5;
        memcpy(&token[1], chal, chal_len);
        memcpy(token + chal_len + 1, digest, MD5_LEN);
    } else {
        token = xstrdup(pass);
    }

    /* get size of submitted data */
    user_len = strlen(user);
    port_len = strlen(tty);
    r_addr_len = strlen(r_addr);
    token_len = strlen(token);

    /* fill the body of message */
    tb.action = action;
    tb.priv_lvl = tac_priv_lvl;
    if (tac_login == NULL) {
        /* default to PAP */
        tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
    } else {
        if (strcmp(tac_login,"chap") == 0) {
            tb.authen_type = TAC_PLUS_AUTHEN_TYPE_CHAP;
        } else if (strcmp(tac_login,"login") == 0) {
            tb.authen_type = TAC_PLUS_AUTHEN_TYPE_ASCII;
        } else {
            tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
        }
    }
    tb.service = tac_authen_service;
    tb.user_len = user_len;
    tb.port_len = port_len;
    tb.r_addr_len = r_addr_len;    /* may be e.g Caller-ID in future */
    tb.data_len = token_len;

    /* fill body length in header */
    bodylength = sizeof(tb) + user_len
        + port_len + r_addr_len + token_len;

    th->datalength = htonl(bodylength);

    /* we can now write the header */
    w = write(fd, th, TAC_PLUS_HDR_SIZE);
    if (w < 0 || w < TAC_PLUS_HDR_SIZE) {
        TACSYSLOG((LOG_ERR,\
            "%s: short write on header, wrote %d of %d: %m",\
            __FUNCTION__, w, TAC_PLUS_HDR_SIZE))
        free(token);
        free(pkt);
        free(th);
        return LIBTAC_STATUS_WRITE_ERR;
    }

    /* build the packet */
    pkt = (u_char *) xcalloc(1, bodylength+10);

    bcopy(&tb, pkt+pkt_len, sizeof(tb)); /* packet body beginning */
    pkt_len += sizeof(tb);
    bcopy(user, pkt+pkt_len, user_len);  /* user */
    pkt_len += user_len;
    bcopy(tty, pkt+pkt_len, port_len);   /* tty */
    pkt_len += port_len;
    bcopy(r_addr, pkt+pkt_len, r_addr_len);   /* rem addr */
    pkt_len += r_addr_len;

    bcopy(token, pkt+pkt_len, token_len);  /* password */
    pkt_len += token_len;

    /* pkt_len == bodylength ? */
    if (pkt_len != bodylength) {
        TACSYSLOG((LOG_ERR, "%s: bodylength %d != pkt_len %d",\
            __FUNCTION__, bodylength, pkt_len))
        free(token);
        free(pkt);
        free(th);
        return LIBTAC_STATUS_ASSEMBLY_ERR;
    } 
        
    /* encrypt the body */
    _tac_crypt(pkt, th, bodylength);

    w = write(fd, pkt, pkt_len);
    if (w < 0 || w < pkt_len) {
        TACSYSLOG((LOG_ERR,\
            "%s: short write on body, wrote %d of %d: %m",\
            __FUNCTION__, w, pkt_len))
        ret = LIBTAC_STATUS_WRITE_ERR;
    }

    /* Packet Debug (In 'debug tacacs packet' format */
    if (ctrl & PAM_TAC_PACKET_DEBUG) {
		char *action_str;
		char *type_str;
		char *service_str;

		authen_action_string(&action_str, tb.action);
		authen_type_string(&type_str, tb.authen_type);
		authen_service_string(&service_str, tb.service);

		TACDEBUG((LOG_DEBUG, "T+: Version %u (0x%02X), type %u, seq %u, encryption %u",
				th->version, th->version, th->type, th->seq_no, th->encryption))
		TACDEBUG((LOG_DEBUG, "T+: session_id %u (0x%08X), dlen %u (0x%02X)",
				th->session_id, th->session_id, th->datalength, th->datalength))
		TACDEBUG((LOG_DEBUG, "T+: type:AUTHEN/START, priv_lvl:%u action:%s %s",
				tb.priv_lvl, action_str, type_str))
		TACDEBUG((LOG_DEBUG, "T+: svc:%s user_len:%u port_len:%u (0x%02X) raddr_len:%u (0x%02X) data_len:%d",
				service_str, tb.user_len, tb.port_len, tb.port_len, tb.r_addr_len,
				tb.r_addr_len, tb.data_len))
		TACDEBUG((LOG_DEBUG, "T+: user:  %s", user))
		TACDEBUG((LOG_DEBUG, "T+: port:  %s", tty))
		TACDEBUG((LOG_DEBUG, "T+: rem_addr:  %s", r_addr))
		/*TACDEBUG((LOG_DEBUG, "T+: data:  %s", token)) hide user password (!)*/
		TACDEBUG((LOG_DEBUG, "T+: data:  <hidden>"))
		TACDEBUG((LOG_DEBUG, "T+: End Packet"))

	    free(action_str);
	    free(type_str);
	    free(service_str);
    }

    free(token);
    free(pkt);
    free(th);

    if (ctrl & PAM_TAC_DEBUG)
    	TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret))
    return ret;
}    /* tac_authen_send */
/*
 * 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);
}