/* Checks given reply header for possible inconsistencies: * 1. reply type other than expected * 2. sequence number other than 2 or 4 * 3. session_id different from one sent in request * Returns pointer to error message * or NULL when the header seems to be correct */ char *_tac_check_header(HDR *th, int type) { if(th->type != type) { TACSYSLOG(LOG_ERR,\ "%s: unrelated reply, type %d, expected %d",\ __FUNCTION__, th->type, type); return protocol_err_msg; } else if (1 == (th->seq_no % 2)) { TACSYSLOG(LOG_ERR, "%s: not a reply - seq_no %d not even",\ __FUNCTION__, th->seq_no); return protocol_err_msg; } /* else if(ntohl(th->session_id) != session_id) { TACSYSLOG(LOG_ERR,\ "%s: unrelated reply, received session_id %d != sent %d",\ __FUNCTION__, ntohl(th->session_id), session_id); return protocol_err_msg; } */ return NULL; /* header is ok */ } /* check header */
/* 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 */
/* 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 */
/* * 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 */