/* 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 */
/* * 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; }
/* 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 */
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); }
void sighandler(int sig __Unused) { TACDEBUG(LOG_DEBUG, "caught signal %d", sig); }