/* * Returns a text string containing the name of the EAP type. */ const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen) { DICT_VALUE *dval; if (type > PW_EAP_MAX_TYPES) { /* * Prefer the dictionary name over a number, * if it exists. */ dval = dict_valbyattr(PW_EAP_TYPE, type); if (dval) { snprintf(buffer, buflen, "%s", dval->name); } snprintf(buffer, buflen, "%d", type); return buffer; } else if ((*eap_types[type] >= '0') && (*eap_types[type] <= '9')) { /* * Prefer the dictionary name, if it exists. */ dval = dict_valbyattr(PW_EAP_TYPE, type); if (dval) { snprintf(buffer, buflen, "%s", dval->name); return buffer; } /* else it wasn't in the dictionary */ } /* else the name in the array was non-numeric */ /* * Return the name, whatever it is. */ return eap_types[type]; }
/** Return an EAP-name for a particular type * * Resolve */ const char *eap_type2name(eap_type_t method) { DICT_VALUE *dv; dv = dict_valbyattr(PW_EAP_TYPE, 0, method); if (dv) { return dv->name; } return "unknown"; }
static int rediswho_accounting(void * instance, REQUEST * request) { int rcode; VALUE_PAIR * vp; DICT_VALUE *dv; CONF_SECTION *cs; const char *insert, *trim, *expire; rlm_rediswho_t *inst = (rlm_rediswho_t *) instance; REDISSOCK *dissocket; vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY); if (!vp) { RDEBUG("Could not find account status type in packet."); return RLM_MODULE_NOOP; } dv = dict_valbyattr(vp->attribute, vp->vendor, vp->vp_integer); if (!dv) { RDEBUG("Unknown Acct-Status-Type %u", vp->vp_integer); return RLM_MODULE_NOOP; } cs = cf_section_sub_find(inst->cs, dv->name); if (!cs) { RDEBUG("No subsection %s", dv->name); return RLM_MODULE_NOOP; } dissocket = fr_connection_get(inst->redis_inst->pool); if (!dissocket) { RDEBUG("cannot allocate redis connection"); return RLM_MODULE_FAIL; } insert = cf_pair_value(cf_pair_find(cs, "insert")); trim = cf_pair_value(cf_pair_find(cs, "trim")); expire = cf_pair_value(cf_pair_find(cs, "expire")); rcode = rediswho_accounting_all(&dissocket, inst, request, insert, trim, expire); if (dissocket) fr_connection_release(inst->redis_inst->pool, dissocket); return rcode; }
/* * Write accounting information to this module's database. */ static int sql_log_accounting(void *instance, REQUEST *request) { int ret; char querystr[MAX_QUERY_LEN]; const char *cfquery; rlm_sql_log_t *inst = (rlm_sql_log_t *)instance; VALUE_PAIR *pair; DICT_VALUE *dval; CONF_PAIR *cp; rad_assert(request != NULL); rad_assert(request->packet != NULL); RDEBUG("Processing sql_log_accounting"); /* Find the Acct Status Type. */ if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) { radlog_request(L_ERR, 0, request, "Packet has no account status type"); return RLM_MODULE_INVALID; } /* Search the query in conf section of the module */ if ((dval = dict_valbyattr(PW_ACCT_STATUS_TYPE, pair->vp_integer)) == NULL) { radlog_request(L_ERR, 0, request, "Unsupported Acct-Status-Type = %d", pair->vp_integer); return RLM_MODULE_NOOP; } if ((cp = cf_pair_find(inst->conf_section, dval->name)) == NULL) { RDEBUG("Couldn't find an entry %s in the config section", dval->name); return RLM_MODULE_NOOP; } cfquery = cf_pair_value(cp); /* Xlat the query */ ret = sql_xlat_query(inst, request, cfquery, querystr, sizeof(querystr)); if (ret != RLM_MODULE_OK) return ret; /* Write query into sql-relay file */ return sql_log_write(inst, request, querystr); }
static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void * instance, REQUEST * request) { rlm_rcode_t rcode; VALUE_PAIR * vp; DICT_VALUE *dv; CONF_SECTION *cs; rlm_rediswho_t *inst = (rlm_rediswho_t *) instance; REDISSOCK *dissocket; vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY); if (!vp) { RDEBUG("Could not find account status type in packet"); return RLM_MODULE_NOOP; } dv = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer); if (!dv) { RDEBUG("Unknown Acct-Status-Type %u", vp->vp_integer); return RLM_MODULE_NOOP; } cs = cf_section_sub_find(inst->cs, dv->name); if (!cs) { RDEBUG("No subsection %s", dv->name); return RLM_MODULE_NOOP; } dissocket = fr_connection_get(inst->redis_inst->pool); if (!dissocket) return RLM_MODULE_FAIL; rcode = mod_accounting_all(&dissocket, inst, request); if (dissocket) fr_connection_release(inst->redis_inst->pool, dissocket); return rcode; }
static int dhcp_process(REQUEST *request) { int rcode; unsigned int i; VALUE_PAIR *vp; dhcp_socket_t *sock; /* * If there's a giaddr, save it as the Relay-IP-Address * in the response. That way the later code knows where * to send the reply. */ vp = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) { VALUE_PAIR *relay; /* DHCP-Relay-IP-Address */ relay = radius_paircreate(request->reply, &request->reply->vps, 272, DHCP_MAGIC_VENDOR); if (relay) relay->vp_ipaddr = vp->vp_ipaddr; } vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer); DEBUG("Trying sub-section dhcp %s {...}", dv->name ? dv->name : "<unknown>"); rcode = process_post_auth(vp->vp_integer, request); } else { DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!"); rcode = RLM_MODULE_FAIL; } vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */ if (vp) { request->reply->code = vp->vp_integer; if ((request->reply->code != 0) && (request->reply->code < PW_DHCP_OFFSET)) { request->reply->code += PW_DHCP_OFFSET; } } else switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = PW_DHCP_OFFER; break; } else if (request->packet->code == PW_DHCP_REQUEST) { request->reply->code = PW_DHCP_ACK; break; } request->reply->code = PW_DHCP_NAK; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = 0; /* ignore the packet */ } else { request->reply->code = PW_DHCP_NAK; } break; case RLM_MODULE_HANDLED: request->reply->code = 0; /* ignore the packet */ break; } /* * TODO: Handle 'output' of RLM_MODULE when acting as a * DHCP relay We may want to not forward packets in * certain circumstances. */ /* * Handle requests when acting as a DHCP relay */ vp = pairfind(request->packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */ if (!vp) { RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!"); return 1; } /* BOOTREPLY received on port 67 (i.e. from a server) */ if (vp->vp_integer == 2) { return dhcprelay_process_server_reply(request); } /* Packet from client, and we have DHCP-Relay-To-IP-Address */ if (pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR, TAG_ANY)) { return dhcprelay_process_client_request(request); } /* else it's a packet from a client, without relaying */ rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */ sock = request->listener->data; /* * Handle requests when acting as a DHCP server */ /* * Releases don't get replies. */ if (request->packet->code == PW_DHCP_RELEASE) { request->reply->code = 0; } if (request->reply->code == 0) { return 1; } request->reply->sockfd = request->packet->sockfd; /* * Copy specific fields from packet to reply, if they * don't already exist */ for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) { uint32_t attr = attrnums[i]; if (pairfind(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue; vp = pairfind(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY); if (vp) { pairadd(&request->reply->vps, paircopyvp(request->reply, vp)); } } vp = pairfind(request->reply->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */ rad_assert(vp != NULL); vp->vp_integer = 2; /* BOOTREPLY */ /* * Allow NAKs to be delayed for a short period of time. */ if (request->reply->code == PW_DHCP_NAK) { vp = pairfind(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY); if (vp) { if (vp->vp_integer <= 10) { request->response_delay = vp->vp_integer; } else { request->response_delay = 10; } } } /* * Prepare the reply packet for sending through dhcp_socket_send() */ request->reply->dst_ipaddr.af = AF_INET; request->reply->src_ipaddr.af = AF_INET; request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr; /* * They didn't set a proper src_ipaddr, but we want to * send the packet with a source IP. If there's a server * identifier, use it. */ if (request->reply->src_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) { vp = pairfind(request->reply->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Server-IP-Address */ if (!vp) vp = pairfind(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */ if (vp) { request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } } request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; /* * Answer to client's nearest DHCP relay. * * Which may be different than the giaddr given in the * packet to the client. i.e. the relay may have a * public IP, but the gateway a private one. */ vp = pairfind(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */ if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) { RDEBUG("DHCP: Reply will be unicast to giaddr from original packet"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; return 1; } /* * Answer to client's nearest DHCP gateway. In this * case, the client can reach the gateway, as can the * server. * * We also use *our* source port as the destination port. * Gateways are servers, and listen on the server port, * not the client port. */ vp = pairfind(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) { RDEBUG("DHCP: Reply will be unicast to giaddr"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->reply->dst_port = request->packet->dst_port; return 1; } /* * If it's a NAK, or the broadcast flag was set, ond * there's no client-ip-address, send a broadcast. */ if ((request->reply->code == PW_DHCP_NAK) || ((vp = pairfind(request->reply->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Flags */ (vp->vp_integer & 0x8000) && ((vp = pairfind(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */ (vp->vp_ipaddr == htonl(INADDR_ANY))))) { /* * RFC 2131, page 23 * * Broadcast on * - DHCPNAK * or * - Broadcast flag is set up and ciaddr == NULL */ RDEBUG("DHCP: Reply will be broadcast"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); return 1; } /* * RFC 2131, page 23 * * Unicast to ciaddr if present, otherwise to yiaddr. */ if ((vp = pairfind(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */ (vp->vp_ipaddr != htonl(INADDR_ANY))) { RDEBUG("DHCP: Reply will be sent unicast to client-ip-address"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; return 1; } vp = pairfind(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */ if (!vp) { RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; " "not responding."); /* * There is nowhere to send the response to, so don't bother. */ request->reply->code = 0; return -1; } #ifdef SIOCSARP /* * The system is configured to listen for broadcast * packets, which means we'll need to send unicast * replies, to IPs which haven't yet been assigned. * Therefore, we need to update the ARP table. * * However, they haven't specified a interface. So we * can't update the ARP table. And we must send a * broadcast response. */ if (sock->lsock.broadcast && !sock->src_interface) { WARN("You MUST set \"interface\" if you have \"broadcast = yes\""); RDEBUG("DHCP: Reply will be broadcast as no interface was defined"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); return 1; } RDEBUG("DHCP: Reply will be unicast to your-ip-address"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; /* * When sending a DHCP_OFFER, make sure our ARP table * contains an entry for the client IP address. * Otherwise the packet may not be sent to the client, as * the OS has no ARP entry for it. * * This is a cute hack to avoid us having to create a raw * socket to send DHCP packets. */ if (request->reply->code == PW_DHCP_OFFER) { VALUE_PAIR *hwvp = pairfind(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */ if (!hwvp) return -1; if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) { RDEBUG("Failed adding arp entry: %s", fr_strerror()); return -1; } } #else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) { RDEBUG("DHCP: Request will be unicast to the unicast source IP address"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr; } else { RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); } #endif return 1; }
static int dhcp_process(REQUEST *request) { int rcode; VALUE_PAIR *vp; vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer); DEBUG("Trying sub-section dhcp %s {...}", dv->name ? dv->name : "<unknown>"); rcode = module_post_auth(vp->vp_integer, request); } else { DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!"); rcode = RLM_MODULE_FAIL; } /* * For messages from a client, look for Relay attribute, * and forward it if necessary. */ vp = NULL; if (request->packet->data[0] == 1) { vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR); } if (vp) { VALUE_PAIR *giaddr; /* * Find the original giaddr. * FIXME: Maybe look in the original packet? * * It's invalid to have giaddr=0 AND a relay option */ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR); if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY))) { if (pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR)) { RDEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet"); return 1; } } if (request->packet->data[3] > 10) { RDEBUG("DHCP: Number of hops is greater than 10: not relaying"); return 1; } /* * Forward a reply... */ pairfree(&request->reply->vps); request->reply->vps = paircopy(request->packet->vps); request->reply->code = request->packet->code; request->reply->id = request->packet->id; request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->src_port = request->packet->dst_port; request->reply->dst_ipaddr.af = AF_INET; request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; /* * Don't change the destination port. It's the * server port. */ /* * Hop count goes up. */ vp = pairfind(request->reply->vps, 259, DHCP_MAGIC_VENDOR); if (vp) vp->vp_integer++; return 1; } /* * Responses from a server. Handle them differently. */ if (request->packet->data[0] == 2) { pairfree(&request->reply->vps); request->reply->vps = paircopy(request->packet->vps); request->reply->code = request->packet->code; request->reply->id = request->packet->id; /* * Delete any existing giaddr. If we received a * message from the server, then we're NOT the * server. So we must be the destination of the * giaddr field. */ pairdelete(&request->packet->vps, 266, DHCP_MAGIC_VENDOR); /* * Search for client IP address. */ vp = pairfind(request->packet->vps, 264, DHCP_MAGIC_VENDOR); if (!vp) { request->reply->code = 0; RDEBUG("DHCP: No YIAddr in the reply. Discarding packet"); return 1; } /* * FROM us, TO the client's IP, OUR port + 1. */ request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->src_port = request->packet->dst_port; request->reply->dst_ipaddr.af = AF_INET; request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->reply->dst_port = request->packet->dst_port + 1; /* * Hop count goes down. */ vp = pairfind(request->reply->vps, 259, DHCP_MAGIC_VENDOR); if (vp && (vp->vp_integer > 0)) vp->vp_integer--; /* * FIXME: Keep original somewhere? If the * broadcast flags are set, use them here? */ return 1; } vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { request->reply->code = vp->vp_integer; if ((request->reply->code != 0) && (request->reply->code < PW_DHCP_OFFSET)) { request->reply->code += PW_DHCP_OFFSET; } } else switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = PW_DHCP_OFFER; break; } else if (request->packet->code == PW_DHCP_REQUEST) { request->reply->code = PW_DHCP_ACK; break; } request->reply->code = PW_DHCP_NAK; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = 0; /* ignore the packet */ } else { request->reply->code = PW_DHCP_NAK; } break; case RLM_MODULE_HANDLED: break; } /* * Releases don't get replies. */ if (request->packet->code == PW_DHCP_RELEASE) { request->reply->code = 0; } return 1; }
/* * Check password. * * Returns: 0 OK * -1 Password fail * -2 Rejected (Auth-Type = Reject, send Port-Message back) * 1 End check & return, don't reply * * NOTE: NOT the same as the RLM_ values ! */ static int rad_check_password(REQUEST *request) { VALUE_PAIR *auth_type_pair; VALUE_PAIR *cur_config_item; VALUE_PAIR *password_pair; VALUE_PAIR *auth_item; uint8_t my_chap[MAX_STRING_LEN]; int auth_type = -1; int result; int auth_type_count = 0; result = 0; /* * Look for matching check items. We skip the whole lot * if the authentication type is PW_AUTHTYPE_ACCEPT or * PW_AUTHTYPE_REJECT. */ cur_config_item = request->config_items; while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE, 0))) != NULL) { DICT_VALUE *dv; auth_type = auth_type_pair->vp_integer; auth_type_count++; dv = dict_valbyattr(auth_type_pair->attribute, auth_type_pair->vp_integer, 0); RDEBUG2("Found Auth-Type = %s", (dv != NULL) ? dv->name : "?"); cur_config_item = auth_type_pair->next; if (auth_type == PW_AUTHTYPE_REJECT) { RDEBUG2("Auth-Type = Reject, rejecting user"); return -2; } } if (( auth_type_count > 1) && (debug_flag)) { radlog_request(L_ERR, 0, request, "Warning: Found %d auth-types on request for user '%s'", auth_type_count, request->username->vp_strvalue); } /* * This means we have a proxy reply or an accept * and it wasn't rejected in the above loop. So * that means it is accepted and we do no further * authentication */ if ((auth_type == PW_AUTHTYPE_ACCEPT) #ifdef WITH_PROXY || (request->proxy) #endif ) { RDEBUG2("Auth-Type = Accept, accepting the user"); return 0; } password_pair = pairfind(request->config_items, PW_USER_PASSWORD, 0); if (password_pair && pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0)) { pairdelete(&request->config_items, PW_USER_PASSWORD, 0); password_pair = NULL; } if (password_pair) { DICT_ATTR *da; RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); RDEBUG("!!! Replacing User-Password in config items with Cleartext-Password. !!!"); RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); RDEBUG("!!! Please update your configuration so that the \"known good\" !!!"); RDEBUG("!!! clear text password is in Cleartext-Password, and not in User-Password. !!!"); RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); password_pair->attribute = PW_CLEARTEXT_PASSWORD; da = dict_attrbyvalue(PW_CLEARTEXT_PASSWORD, 0); if (!da) { radlog_request(L_ERR, 0, request, "FATAL: You broke the dictionaries. Please use the default dictionaries!"); _exit(1); } password_pair->name = da->name; } /* * Find the "known good" password. * * FIXME: We should get rid of these hacks, and replace * them with a module. */ if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD, 0)) != NULL) { /* * Re-write Auth-Type, but ONLY if it isn't already * set. */ if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT; } else { password_pair = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); } if (auth_type < 0) { if (password_pair) { auth_type = PW_AUTHTYPE_LOCAL; } else { /* * The admin hasn't told us how to * authenticate the user, so we reject them! * * This is fail-safe. */ RDEBUG2("ERROR: No authenticate method (Auth-Type) found for the request: Rejecting the user"); return -2; } } switch(auth_type) { case PW_AUTHTYPE_CRYPT: RDEBUG2("WARNING: Please update your configuration, and remove 'Auth-Type = Crypt'"); RDEBUG2("WARNING: Use the PAP module instead."); /* * Find the password sent by the user. It * SHOULD be there, if it's not * authentication fails. */ auth_item = request->password; if (auth_item == NULL) { RDEBUG2("No User-Password or CHAP-Password attribute in the request"); return -1; } if (password_pair == NULL) { RDEBUG2("No Crypt-Password configured for the user"); rad_authlog("Login incorrect " "(No Crypt-Password configured for the user)", request, 0); return -1; } switch (fr_crypt_check((char *)auth_item->vp_strvalue, (char *)password_pair->vp_strvalue)) { case -1: rad_authlog("Login incorrect " "(system failed to supply an encrypted password for comparison)", request, 0); case 1: return -1; } break; case PW_AUTHTYPE_LOCAL: RDEBUG2("WARNING: Please update your configuration, and remove 'Auth-Type = Local'"); RDEBUG2("WARNING: Use the PAP or CHAP modules instead."); /* * Find the password sent by the user. It * SHOULD be there, if it's not * authentication fails. */ auth_item = request->password; if (!auth_item) auth_item = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0); if (!auth_item) { RDEBUG2("No User-Password or CHAP-Password attribute in the request."); RDEBUG2("Cannot perform authentication."); return -1; } /* * Plain text password. */ if (password_pair == NULL) { RDEBUG2("No \"known good\" password was configured for the user."); RDEBUG2("As a result, we cannot authenticate the user."); rad_authlog("Login incorrect " "(No password configured for the user)", request, 0); return -1; } /* * Local password is just plain text. */ if (auth_item->attribute == PW_USER_PASSWORD) { if (strcmp((char *)password_pair->vp_strvalue, (char *)auth_item->vp_strvalue) != 0) { RDEBUG2("User-Password in the request does NOT match \"known good\" password."); return -1; } RDEBUG2("User-Password in the request is correct."); break; } else if (auth_item->attribute != PW_CHAP_PASSWORD) { RDEBUG2("The user did not supply a User-Password or a CHAP-Password attribute"); rad_authlog("Login incorrect " "(no User-Password or CHAP-Password attribute)", request, 0); return -1; } rad_chap_encode(request->packet, my_chap, auth_item->vp_octets[0], password_pair); /* * Compare them */ if (memcmp(my_chap + 1, auth_item->vp_strvalue + 1, CHAP_VALUE_LENGTH) != 0) { RDEBUG2("CHAP-Password is incorrect."); return -1; } RDEBUG2("CHAP-Password is correct."); break; default: /* * See if there is a module that handles * this type, and turn the RLM_ return * status into the values as defined at * the top of this function. */ result = module_authenticate(auth_type, request); switch (result) { /* * An authentication module FAIL * return code, or any return code that * is not expected from authentication, * is the same as an explicit REJECT! */ case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: case RLM_MODULE_REJECT: case RLM_MODULE_UPDATED: case RLM_MODULE_USERLOCK: default: result = -1; break; case RLM_MODULE_OK: result = 0; break; case RLM_MODULE_HANDLED: result = 1; break; } break; } return result; }
/* * Dynamically translate for check:, request:, reply:, etc. */ static size_t xlat_packet(void *instance, REQUEST *request, const char *fmt, char *out, size_t outlen) { DICT_ATTR *da; VALUE_PAIR *vp; VALUE_PAIR *vps = NULL; RADIUS_PACKET *packet = NULL; switch (*(int*) instance) { case 0: vps = request->config_items; break; case 1: vps = request->packet->vps; packet = request->packet; break; case 2: vps = request->reply->vps; packet = request->reply; break; case 3: #ifdef WITH_PROXY if (request->proxy) vps = request->proxy->vps; packet = request->proxy; #endif break; case 4: #ifdef WITH_PROXY if (request->proxy_reply) vps = request->proxy_reply->vps; packet = request->proxy_reply; #endif break; case 5: if (request->parent) { vps = request->parent->packet->vps; packet = request->parent->packet; } break; case 6: if (request->parent && request->parent->reply) { vps = request->parent->reply->vps; packet = request->parent->reply; } break; case 7: if (request->parent) { vps = request->parent->config_items; } break; default: /* WTF? */ return 0; } /* * The "format" string is the attribute name. */ da = dict_attrbyname(fmt); if (!da) { int do_number = FALSE; int do_array = FALSE; int do_count = FALSE; int do_all = FALSE; int tag = 0; size_t count = 0, total; char *p; char buffer[256]; if (strlen(fmt) > sizeof(buffer)) return 0; strlcpy(buffer, fmt, sizeof(buffer)); /* * %{Attribute-name#} - print integer version of it. */ p = buffer + strlen(buffer) - 1; if (*p == '#') { *p = '\0'; do_number = TRUE; } /* * %{Attribute-Name:tag} - get the name with the specified * value of the tag. */ p = strchr(buffer, ':'); if (p) { tag = atoi(p + 1); *p = '\0'; p++; } else { /* * Allow %{Attribute-Name:tag[...]} */ p = buffer; } /* * %{Attribute-Name[...] does more stuff */ p = strchr(p, '['); if (p) { *p = '\0'; do_array = TRUE; if (p[1] == '#') { do_count = TRUE; } else if (p[1] == '*') { do_all = TRUE; } else { count = atoi(p + 1); p += 1 + strspn(p + 1, "0123456789"); if (*p != ']') { RDEBUG2("xlat: Invalid array reference in string at %s %s", fmt, p); return 0; } } } /* * We COULD argue about %{Attribute-Name[#]#} etc. * But that looks like more work than it's worth. */ da = dict_attrbyname(buffer); if (!da) return 0; /* * No array, print the tagged attribute. */ if (!do_array) { vp = pairfind_tag(vps, da, tag); goto just_print; } total = 0; /* * Array[#] - return the total */ if (do_count) { for (vp = pairfind_tag(vps, da, tag); vp != NULL; vp = pairfind_tag(vp->next, da, tag)) { total++; } snprintf(out, outlen, "%d", (int) total); return strlen(out); } /* * %{Attribute-Name[*]} returns ALL of the * the attributes, separated by a newline. */ if (do_all) { for (vp = pairfind_tag(vps, da, tag); vp != NULL; vp = pairfind_tag(vp->next, da, tag)) { count = valuepair2str(out, outlen - 1, vp, da->type); rad_assert(count <= outlen); total += count + 1; outlen -= (count + 1); out += count; *(out++) = '\n'; if (outlen <= 1) break; } *out = '\0'; return total; } /* * Find the N'th value. */ for (vp = pairfind_tag(vps, da, tag); vp != NULL; vp = pairfind_tag(vp->next, da, tag)) { if (total == count) break; total++; if (total > count) { vp = NULL; break; } } /* * Non-existent array reference. */ just_print: if (!vp) return 0; if (do_number) { if ((vp->type != PW_TYPE_IPADDR) && (vp->type != PW_TYPE_INTEGER) && (vp->type != PW_TYPE_SHORT) && (vp->type != PW_TYPE_BYTE) && (vp->type != PW_TYPE_DATE)) { *out = '\0'; return 0; } return snprintf(out, outlen, "%u", vp->vp_integer); } return valuepair2str(out, outlen, vp, da->type); } vp = pairfind(vps, da->attr, da->vendor); if (!vp) { /* * Some "magic" handlers, which are never in VP's, but * which are in the packet. * * @bug FIXME: We should really do this in a more * intelligent way... */ if (packet) { VALUE_PAIR localvp; memset(&localvp, 0, sizeof(localvp)); switch (da->attr) { case PW_PACKET_TYPE: { DICT_VALUE *dval; dval = dict_valbyattr(da->attr, da->vendor, packet->code); if (dval) { snprintf(out, outlen, "%s", dval->name); } else { snprintf(out, outlen, "%d", packet->code); } return strlen(out); } break; case PW_CLIENT_SHORTNAME: if (request->client && request->client->shortname) { strlcpy(out, request->client->shortname, outlen); } else { strlcpy(out, "<UNKNOWN-CLIENT>", outlen); } return strlen(out); case PW_CLIENT_IP_ADDRESS: /* the same as below */ case PW_PACKET_SRC_IP_ADDRESS: if (packet->src_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; localvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr; break; case PW_PACKET_DST_IP_ADDRESS: if (packet->dst_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; localvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; break; case PW_PACKET_SRC_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->src_port; break; case PW_PACKET_DST_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->dst_port; break; case PW_PACKET_AUTHENTICATION_VECTOR: localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, packet->vector, sizeof(packet->vector)); localvp.length = sizeof(packet->vector); break; /* * Authorization, accounting, etc. */ case PW_REQUEST_PROCESSING_STAGE: if (request->component) { strlcpy(out, request->component, outlen); } else { strlcpy(out, "server_core", outlen); } return strlen(out); case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af != AF_INET6) { return 0; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &packet->src_ipaddr.ipaddr.ip6addr, sizeof(packet->src_ipaddr.ipaddr.ip6addr)); break; case PW_PACKET_DST_IPV6_ADDRESS: if (packet->dst_ipaddr.af != AF_INET6) { return 0; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); break; case PW_VIRTUAL_SERVER: if (!request->server) return 0; snprintf(out, outlen, "%s", request->server); return strlen(out); break; case PW_MODULE_RETURN_CODE: localvp.attribute = da->attr; /* * See modcall.c for a bit of a hack. */ localvp.vp_integer = request->simul_max; break; default: return 0; /* not found */ break; } localvp.type = da->type; return valuepair2str(out, outlen, &localvp, da->type); } /* * Not found, die. */ return 0; } if (!vps) return 0; /* silently fail */ /* * Convert the VP to a string, and return it. */ return valuepair2str(out, outlen, vp, da->type); }
/** * @brief Dynamically translate for check:, request:, reply:, etc. */ static size_t xlat_packet(void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, RADIUS_ESCAPE_STRING func) { DICT_ATTR *da; VALUE_PAIR *vp; VALUE_PAIR *vps = NULL; RADIUS_PACKET *packet = NULL; switch (*(int*) instance) { case 0: vps = request->config_items; break; case 1: vps = request->packet->vps; packet = request->packet; break; case 2: vps = request->reply->vps; packet = request->reply; break; case 3: #ifdef WITH_PROXY if (request->proxy) vps = request->proxy->vps; packet = request->proxy; #endif break; case 4: #ifdef WITH_PROXY if (request->proxy_reply) vps = request->proxy_reply->vps; packet = request->proxy_reply; #endif break; case 5: if (request->parent) { vps = request->parent->packet->vps; packet = request->parent->packet; } break; case 6: if (request->parent && request->parent->reply) { vps = request->parent->reply->vps; packet = request->parent->reply; } break; case 7: if (request->parent) { vps = request->parent->config_items; } break; default: /* WTF? */ return 0; } /* * The "format" string is the attribute name. */ da = dict_attrbyname(fmt); if (!da) { int do_number = FALSE; size_t count; const char *p; char buffer[256]; if (strlen(fmt) > sizeof(buffer)) return 0; p = strchr(fmt, '['); if (!p) { p = strchr(fmt, '#'); if (!p) return 0; do_number = TRUE; } strlcpy(buffer, fmt, p - fmt + 1); da = dict_attrbyname(buffer); if (!da) return 0; if (do_number) { vp = pairfind(vps, da->attr, 0); if (!vp) return 0; switch (da->type) { default: break; case PW_TYPE_INTEGER: case PW_TYPE_DATE: case PW_TYPE_SHORT: case PW_TYPE_BYTE: snprintf(out, outlen, "%u", vp->lvalue); return strlen(out); } goto just_print; } /* * %{Attribute-Name[#]} returns the count of * attributes of that name in the list. */ if ((p[1] == '#') && (p[2] == ']')) { count = 0; for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; vp = pairfind(vp->next, da->attr, da->vendor)) { count++; } snprintf(out, outlen, "%d", (int) count); return strlen(out); } /* * %{Attribute-Name[*]} returns ALL of the * the attributes, separated by a newline. */ if ((p[1] == '*') && (p[2] == ']')) { int total = 0; for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; vp = pairfind(vp->next, da->attr, da->vendor)) { count = valuepair2str(out, outlen - 1, vp, da->type, func); rad_assert(count <= outlen); total += count + 1; outlen -= (count + 1); out += count; *(out++) = '\n'; if (outlen <= 1) break; } *out = '\0'; return total; } count = atoi(p + 1); /* * Skip the numbers. */ p += 1 + strspn(p + 1, "0123456789"); if (*p != ']') { RDEBUG2("xlat: Invalid array reference in string at %s %s", fmt, p); return 0; } /* * Find the N'th value. */ for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; vp = pairfind(vp->next, da->attr, da->vendor)) { if (count == 0) break; count--; } /* * Non-existent array reference. */ if (!vp) return 0; just_print: return valuepair2str(out, outlen, vp, da->type, func); } vp = pairfind(vps, da->attr, da->vendor); if (!vp) { /* * Some "magic" handlers, which are never in VP's, but * which are in the packet. * * @bug FIXME: We should really do this in a more * intelligent way... */ if (packet) { VALUE_PAIR localvp; memset(&localvp, 0, sizeof(localvp)); switch (da->attr) { case PW_PACKET_TYPE: { DICT_VALUE *dval; dval = dict_valbyattr(da->attr, da->vendor, packet->code); if (dval) { snprintf(out, outlen, "%s", dval->name); } else { snprintf(out, outlen, "%d", packet->code); } return strlen(out); } break; case PW_CLIENT_SHORTNAME: if (request->client && request->client->shortname) { strlcpy(out, request->client->shortname, outlen); } else { strlcpy(out, "<UNKNOWN-CLIENT>", outlen); } return strlen(out); case PW_CLIENT_IP_ADDRESS: /* the same as below */ case PW_PACKET_SRC_IP_ADDRESS: if (packet->src_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; localvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr; break; case PW_PACKET_DST_IP_ADDRESS: if (packet->dst_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; localvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; break; case PW_PACKET_SRC_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->src_port; break; case PW_PACKET_DST_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->dst_port; break; case PW_PACKET_AUTHENTICATION_VECTOR: localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, packet->vector, sizeof(packet->vector)); localvp.length = sizeof(packet->vector); break; /* * Authorization, accounting, etc. */ case PW_REQUEST_PROCESSING_STAGE: if (request->component) { strlcpy(out, request->component, outlen); } else { strlcpy(out, "server_core", outlen); } return strlen(out); case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af != AF_INET6) { return 0; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &packet->src_ipaddr.ipaddr.ip6addr, sizeof(packet->src_ipaddr.ipaddr.ip6addr)); break; case PW_PACKET_DST_IPV6_ADDRESS: if (packet->dst_ipaddr.af != AF_INET6) { return 0; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); break; case PW_VIRTUAL_SERVER: if (!request->server) return 0; snprintf(out, outlen, "%s", request->server); return strlen(out); break; case PW_MODULE_RETURN_CODE: localvp.attribute = da->attr; /* * See modcall.c for a bit of a hack. */ localvp.vp_integer = request->simul_max; break; default: return 0; /* not found */ break; } localvp.type = da->type; return valuepair2str(out, outlen, &localvp, da->type, func); } /* * Not found, die. */ return 0; } if (!vps) return 0; /* silently fail */ /* * Convert the VP to a string, and return it. */ return valuepair2str(out, outlen, vp, da->type, func); }
static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, pair_lists_t list, DICT_ATTR const *da, int8_t tag, bool return_null) { VALUE_PAIR *vp, *vps = NULL; RADIUS_PACKET *packet = NULL; DICT_VALUE *dv; VALUE_PAIR myvp; /* * Arg. Too much abstraction is annoying. */ switch (list) { default: if (return_null) return NULL; return vp_aprinttype(ctx, da->type); case PAIR_LIST_CONTROL: vps = request->config_items; break; case PAIR_LIST_REQUEST: packet = request->packet; if (packet) vps = packet->vps; break; case PAIR_LIST_REPLY: packet = request->reply; if (packet) vps = packet->vps; break; #if WITH_PROXY case PAIR_LIST_PROXY_REQUEST: packet = request->proxy; if (packet) vps = packet->vps; break; case PAIR_LIST_PROXY_REPLY: packet = request->proxy_reply; if (packet) vps = packet->vps; break; #endif #ifdef WITH_COA case PAIR_LIST_COA: case PAIR_LIST_DM: if (request->coa) packet = request->coa->packet; if (packet) vps = packet->vps; break; case PAIR_LIST_COA_REPLY: case PAIR_LIST_DM_REPLY: if (request->coa) packet = request->coa->reply; if (packet) vps = packet->vps; break; #endif } /* * Now that we have the list, etc. handled, * find the VP and print it. */ if ((da->vendor != 0) || (da->attr < 256) || (list == PAIR_LIST_CONTROL)) { print_vp: vp = pairfind(vps, da->attr, da->vendor, tag); goto do_print; } /* * Some non-packet expansions */ switch (da->attr) { default: break; /* ignore them */ case PW_CLIENT_SHORTNAME: if (request->client && request->client->shortname) { return talloc_strdup(ctx, request->client->shortname); } return talloc_strdup(ctx, "<UNKNOWN-CLIENT>"); case PW_REQUEST_PROCESSING_STAGE: if (request->component) { return talloc_strdup(ctx, request->component); } return talloc_strdup(ctx, "server_core"); case PW_VIRTUAL_SERVER: if (!request->server) return NULL; return talloc_strdup(ctx, request->server); case PW_MODULE_RETURN_CODE: return talloc_asprintf(ctx, "%d", request->simul_max); /* hack */ } /* * All of the attributes must now refer to a packet. If * there's no packet, we can't print any attribute * referencing it. */ if (!packet) { if (return_null) return NULL; return vp_aprinttype(ctx, da->type); } memset(&myvp, 0, sizeof(myvp)); myvp.da = da; vp = NULL; switch (da->attr) { default: goto print_vp; case PW_PACKET_TYPE: dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code); if (dv) return talloc_strdup(ctx, dv->name); return talloc_asprintf(ctx, "%d", packet->code); case PW_PACKET_AUTHENTICATION_VECTOR: myvp.length = sizeof(packet->vector); memcpy(&myvp.vp_octets, packet->vector, sizeof(packet->vector)); vp = &myvp; break; case PW_CLIENT_IP_ADDRESS: case PW_PACKET_SRC_IP_ADDRESS: if (packet->src_ipaddr.af == AF_INET) { myvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr; vp = &myvp; } break; case PW_PACKET_DST_IP_ADDRESS: if (packet->dst_ipaddr.af == AF_INET) { myvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; vp = &myvp; } break; case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af == AF_INET6) { memcpy(&myvp.vp_ipv6addr, &packet->src_ipaddr.ipaddr.ip6addr, sizeof(packet->src_ipaddr.ipaddr.ip6addr)); vp = &myvp; } break; case PW_PACKET_DST_IPV6_ADDRESS: if (packet->dst_ipaddr.af == AF_INET6) { memcpy(&myvp.vp_ipv6addr, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); vp = &myvp; } break; case PW_PACKET_SRC_PORT: myvp.vp_integer = packet->src_port; vp = &myvp; break; case PW_PACKET_DST_PORT: myvp.vp_integer = packet->dst_port; vp = &myvp; break; } do_print: if (!vp) { if (return_null) return NULL; return vp_aprinttype(ctx, da->type); } return vp_aprint(ctx, vp); }
static int dhcp_process(REQUEST *request) { int rcode; unsigned int i; VALUE_PAIR *vp; dhcp_socket_t *sock; vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer); DEBUG("Trying sub-section dhcp %s {...}", dv->name ? dv->name : "<unknown>"); rcode = module_post_auth(vp->vp_integer, request); } else { DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!"); rcode = RLM_MODULE_FAIL; } vp = pairfind(request->reply->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */ if (vp) { request->reply->code = vp->vp_integer; if ((request->reply->code != 0) && (request->reply->code < PW_DHCP_OFFSET)) { request->reply->code += PW_DHCP_OFFSET; } } else switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = PW_DHCP_OFFER; break; } else if (request->packet->code == PW_DHCP_REQUEST) { request->reply->code = PW_DHCP_ACK; break; } request->reply->code = PW_DHCP_NAK; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = 0; /* ignore the packet */ } else { request->reply->code = PW_DHCP_NAK; } break; case RLM_MODULE_HANDLED: request->reply->code = 0; /* ignore the packet */ break; } /* * TODO: Handle 'output' of RLM_MODULE when acting as a * DHCP relay We may want to not forward packets in * certain circumstances. */ /* * Handle requests when acting as a DHCP relay */ vp = pairfind(request->packet->vps, DHCP2ATTR(256)); /* DHCP-Opcode */ if (!vp) { RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!"); return 1; } /* BOOTREPLY received on port 67 (i.e. from a server) */ if (vp->vp_integer == 2) { return dhcprelay_process_server_reply(request); } /* Packet from client, and we have DHCP-Relay-To-IP-Address */ if (pairfind(request->config_items, DHCP2ATTR(270))) { return dhcprelay_process_client_request(request); } /* else it's a packet from a client, without relaying */ rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */ sock = request->listener->data; /* * Handle requests when acting as a DHCP server */ /* * Releases don't get replies. */ if (request->packet->code == PW_DHCP_RELEASE) { request->reply->code = 0; } if (request->reply->code == 0) { return 1; } request->reply->sockfd = request->packet->sockfd; /* * Copy specific fields from packet to reply, if they * don't already exist */ for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) { uint32_t attr = attrnums[i]; if (pairfind(request->reply->vps, DHCP2ATTR(attr))) continue; if ((vp = pairfind(request->packet->vps, DHCP2ATTR(attr)))) { pairadd(&request->reply->vps, paircopyvp(vp)); } } vp = pairfind(request->reply->vps, DHCP2ATTR(256)); /* DHCP-Opcode */ rad_assert(vp != NULL); vp->vp_integer = 2; /* BOOTREPLY */ /* * Prepare the reply packet for sending through dhcp_socket_send() */ request->reply->dst_ipaddr.af = AF_INET; request->reply->src_ipaddr.af = AF_INET; request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr; request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; vp = pairfind(request->reply->vps, DHCP2ATTR(266)); /* DHCP-Gateway-IP-Address */ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) { /* Answer to client's nearest DHCP relay */ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else if ((request->reply->code == PW_DHCP_NAK) || ((vp = pairfind(request->reply->vps, DHCP2ATTR(262))) /* DHCP-Flags */ && (vp->vp_integer & 0x8000) && ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ && (vp->vp_ipaddr == htonl(INADDR_ANY))))) { /* * RFC 2131, page 23 * * Broadcast on * - DHCPNAK * or * - Broadcast flag is set up and ciaddr == NULL */ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); } else { /* * RFC 2131, page 23 * * Unicast to * - ciaddr if present * otherwise to yiaddr */ if ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ && (vp->vp_ipaddr != htonl(INADDR_ANY))) { request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else { vp = pairfind(request->reply->vps, DHCP2ATTR(264)); /* DHCP-Your-IP-Address */ if (!vp) { DEBUG("DHCP: Failed to find IP Address for request."); return -1; } request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; /* * When sending a DHCP_OFFER, make sure our ARP table * contains an entry for the client IP address, or else * packet may not be forwarded if it was the first time * the client was requesting an IP address. */ if (request->reply->code == PW_DHCP_OFFER) { VALUE_PAIR *hwvp = pairfind(request->reply->vps, DHCP2ATTR(267)); /* DHCP-Client-Hardware-Address */ if (!hwvp) return -1; if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) { return -1; } } } } return 1; }
/* * Print one value into a string. * delimitst will define if strings and dates will be delimited by '"' */ int vp_prints_value(char * out, size_t outlen, VALUE_PAIR *vp, int delimitst) { DICT_VALUE *v; char buf[1024]; const char *a = NULL; size_t len; time_t t; struct tm s_tm; out[0] = '\0'; if (!vp) return 0; switch (vp->type) { case PW_TYPE_STRING: if ((delimitst == 1) && vp->flags.has_tag) { /* Tagged attribute: print delimter and ignore tag */ buf[0] = '"'; fr_print_string(vp->vp_strvalue, vp->length, buf + 1, sizeof(buf) - 2); strcat(buf, "\""); } else if (delimitst == 1) { /* Non-tagged attribute: print delimter */ buf[0] = '"'; fr_print_string(vp->vp_strvalue, vp->length, buf + 1, sizeof(buf) - 2); strcat(buf, "\""); } else if (delimitst < 0) { /* xlat.c */ strlcpy(out, vp->vp_strvalue, outlen); return strlen(out); } else { /* Non-tagged attribute: no delimiter */ fr_print_string(vp->vp_strvalue, vp->length, buf, sizeof(buf)); } a = buf; break; case PW_TYPE_INTEGER: if ( vp->flags.has_tag ) { /* Attribute value has a tag, need to ignore it */ if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff))) != NULL) a = v->name; else { snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff)); a = buf; } } else { case PW_TYPE_BYTE: case PW_TYPE_SHORT: /* Normal, non-tagged attribute */ if ((v = dict_valbyattr(vp->attribute, vp->vp_integer)) != NULL) a = v->name; else { snprintf(buf, sizeof(buf), "%u", vp->vp_integer); a = buf; } } break; case PW_TYPE_DATE: t = vp->vp_date; if (delimitst == 1) { len = strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"", localtime_r(&t, &s_tm)); } else { len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm)); } if (len > 0) a = buf; break; case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */ snprintf(buf, sizeof(buf), "%d", vp->vp_signed); a = buf; break; case PW_TYPE_IPADDR: a = inet_ntop(AF_INET, &(vp->vp_ipaddr), buf, sizeof(buf)); break; case PW_TYPE_ABINARY: #ifdef ASCEND_BINARY a = buf; print_abinary(vp, buf, sizeof(buf)); break; #else /* FALL THROUGH */ #endif case PW_TYPE_OCTETS: if (outlen <= (2 * (vp->length + 1))) return 0; strcpy(buf, "0x"); fr_bin2hex(vp->vp_octets, buf + 2, vp->length); a = buf; break; case PW_TYPE_IFID: a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets); break; case PW_TYPE_IPV6ADDR: a = inet_ntop(AF_INET6, (const struct in6_addr *) vp->vp_strvalue, buf, sizeof(buf)); break; case PW_TYPE_IPV6PREFIX: { struct in6_addr addr; /* * Alignment issues. */ memcpy(&addr, vp->vp_strvalue + 2, sizeof(addr)); a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf)); if (a) { char *p = buf + strlen(buf); snprintf(p, buf + sizeof(buf) - p - 1, "/%u", (unsigned int) vp->vp_octets[1]); } } break; case PW_TYPE_ETHERNET: snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", vp->vp_ether[0], vp->vp_ether[1], vp->vp_ether[2], vp->vp_ether[3], vp->vp_ether[4], vp->vp_ether[5]); a = buf; break; case PW_TYPE_TLV: if (outlen <= (2 * (vp->length + 1))) return 0; strcpy(buf, "0x"); fr_bin2hex(vp->vp_tlv, buf + 2, vp->length); a = buf; break; default: a = "UNKNOWN-TYPE"; break; } if (a != NULL) strlcpy(out, a, outlen); return strlen(out); }
/* * Check password. * * Returns: 0 OK * -1 Password fail * -2 Rejected (Auth-Type = Reject, send Port-Message back) * 1 End check & return, don't reply * * NOTE: NOT the same as the RLM_ values ! */ static int rad_check_password(REQUEST *request) { VALUE_PAIR *auth_type_pair; VALUE_PAIR *cur_config_item; VALUE_PAIR *password_pair; VALUE_PAIR *auth_item; DICT_VALUE *da; char string[MAX_STRING_LEN]; int auth_type = -1; int result; int auth_type_count = 0; result = 0; /* * Look for matching check items. We skip the whole lot * if the authentication type is PW_AUTHTYPE_ACCEPT or * PW_AUTHTYPE_REJECT. */ cur_config_item = request->config_items; while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) { auth_type = auth_type_pair->lvalue; auth_type_count++; DEBUG2(" rad_check_password: Found Auth-Type %s", auth_type_pair->strvalue); cur_config_item = auth_type_pair->next; if (auth_type == PW_AUTHTYPE_REJECT) { DEBUG2(" rad_check_password: Auth-Type = Reject, rejecting user"); return -2; } } if (( auth_type_count > 1) && (debug_flag)) { radlog(L_ERR, "Warning: Found %d auth-types on request for user '%s'", auth_type_count, request->username->strvalue); } /* * This means we have a proxy reply or an accept * and it wasn't rejected in the above loop. So * that means it is accepted and we do no further * authentication */ if ((auth_type == PW_AUTHTYPE_ACCEPT) || (request->proxy)) { DEBUG2(" rad_check_password: Auth-Type = Accept, accepting the user"); return 0; } /* * Find the password from the users file. */ if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) { /* * Re-write Auth-Type, but ONLY if it isn't already * set. */ if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT; } else { password_pair = pairfind(request->config_items, PW_PASSWORD); } if (auth_type < 0) { if (password_pair) { auth_type = PW_AUTHTYPE_LOCAL; } else { /* * The admin hasn't told us how to * authenticate the user, so we reject them! * * This is fail-safe. */ DEBUG2("auth: No authenticate method (Auth-Type) configuration found for the request: Rejecting the user"); return -2; } } switch(auth_type) { case PW_AUTHTYPE_CRYPT: /* * Find the password sent by the user. It * SHOULD be there, if it's not * authentication fails. */ auth_item = request->password; if (auth_item == NULL) { DEBUG2("auth: No User-Password or CHAP-Password attribute in the request"); return -1; } DEBUG2("auth: type Crypt"); if (password_pair == NULL) { DEBUG2("No Crypt-Password configured for the user"); rad_authlog("Login incorrect " "(No Crypt-Password configured for the user)", request, 0); return -1; } switch (lrad_crypt_check((char *)auth_item->strvalue, (char *)password_pair->strvalue)) { case -1: rad_authlog("Login incorrect " "(system failed to supply an encrypted password for comparison)", request, 0); case 1: return -1; } break; case PW_AUTHTYPE_LOCAL: DEBUG2("auth: type Local"); /* * Find the password sent by the user. It * SHOULD be there, if it's not * authentication fails. */ auth_item = request->password; if (auth_item == NULL) { DEBUG2("auth: No User-Password or CHAP-Password attribute in the request"); return -1; } /* * Plain text password. */ if (password_pair == NULL) { DEBUG2("auth: No password configured for the user"); rad_authlog("Login incorrect " "(No password configured for the user)", request, 0); return -1; } /* * Local password is just plain text. */ if (auth_item->attribute == PW_PASSWORD) { if (strcmp((char *)password_pair->strvalue, (char *)auth_item->strvalue) != 0) { DEBUG2("auth: user supplied User-Password does NOT match local User-Password"); return -1; } DEBUG2("auth: user supplied User-Password matches local User-Password"); break; } else if (auth_item->attribute != PW_CHAP_PASSWORD) { DEBUG2("The user did not supply a User-Password or a CHAP-Password attribute"); rad_authlog("Login incorrect " "(no User-Password or CHAP-Password attribute)", request, 0); return -1; } rad_chap_encode(request->packet, string, auth_item->strvalue[0], password_pair); /* * Compare them */ if (memcmp(string + 1, auth_item->strvalue + 1, CHAP_VALUE_LENGTH) != 0) { DEBUG2("auth: user supplied CHAP-Password does NOT match local User-Password"); return -1; } DEBUG2("auth: user supplied CHAP-Password matches local User-Password"); break; default: da = dict_valbyattr(PW_AUTH_TYPE, auth_type); DEBUG2("auth: type \"%s\"", da->name); /* * See if there is a module that handles * this type, and turn the RLM_ return * status into the values as defined at * the top of this function. */ result = module_authenticate(auth_type, request); switch (result) { /* * An authentication module FAIL * return code, or any return code that * is not expected from authentication, * is the same as an explicit REJECT! */ case RLM_MODULE_FAIL: case RLM_MODULE_REJECT: case RLM_MODULE_USERLOCK: case RLM_MODULE_INVALID: case RLM_MODULE_NOTFOUND: case RLM_MODULE_NOOP: case RLM_MODULE_UPDATED: result = -1; break; case RLM_MODULE_OK: result = 0; break; case RLM_MODULE_HANDLED: result = 1; break; } break; } return result; }
/* * Calculate/check digest, and decode radius attributes. */ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret) { DICT_ATTR *attr; uint32_t lvalue; uint32_t vendorcode; VALUE_PAIR **tail; VALUE_PAIR *pair; uint8_t *ptr; int length; int attribute; int attrlen; int vendorlen; radius_packet_t *hdr; hdr = (radius_packet_t *)packet->data; /* * Before we allocate memory for the attributes, do more * sanity checking. */ ptr = hdr->data; length = packet->data_len - AUTH_HDR_LEN; while (length > 0) { uint8_t msg_auth_vector[AUTH_VECTOR_LEN]; uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; attrlen = ptr[1]; switch (ptr[0]) { default: /* don't do anything. */ break; /* * Note that more than one Message-Authenticator * attribute is invalid. */ case PW_MESSAGE_AUTHENTICATOR: memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector)); memset(&ptr[2], 0, AUTH_VECTOR_LEN); switch (packet->code) { default: break; case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: if (original) { memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN); } break; } lrad_hmac_md5(packet->data, packet->data_len, secret, strlen(secret), calc_auth_vector); if (memcmp(calc_auth_vector, msg_auth_vector, sizeof(calc_auth_vector)) != 0) { char buffer[32]; librad_log("Received packet from %s with invalid Message-Authenticator! (Shared secret is incorrect.)", ip_ntoa(buffer, packet->src_ipaddr)); return 1; } /* else the message authenticator was good */ /* * Reinitialize Authenticators. */ memcpy(&ptr[2], msg_auth_vector, AUTH_VECTOR_LEN); memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN); break; } /* switch over the attributes */ ptr += attrlen; length -= attrlen; } /* loop over the packet, sanity checking the attributes */ /* * Calculate and/or verify digest. */ switch(packet->code) { int rcode; case PW_AUTHENTICATION_REQUEST: case PW_STATUS_SERVER: case PW_DISCONNECT_REQUEST: /* * The authentication vector is random * nonsense, invented by the client. */ break; case PW_ACCOUNTING_REQUEST: if (calc_acctdigest(packet, secret) > 1) { char buffer[32]; librad_log("Received Accounting-Request packet " "from %s with invalid signature! (Shared secret is incorrect.)", ip_ntoa(buffer, packet->src_ipaddr)); return 1; } break; /* Verify the reply digest */ case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCOUNTING_RESPONSE: rcode = calc_replydigest(packet, original, secret); if (rcode > 1) { char buffer[32]; librad_log("Received %s packet " "from %s with invalid signature (err=%d)! (Shared secret is incorrect.)", packet_codes[packet->code], ip_ntoa(buffer, packet->src_ipaddr), rcode); return 1; } break; } /* * Extract attribute-value pairs */ ptr = hdr->data; length = packet->data_len - AUTH_HDR_LEN; packet->vps = NULL; tail = &packet->vps; vendorcode = 0; vendorlen = 0; while(length > 0) { if (vendorlen > 0) { attribute = *ptr++ | (vendorcode << 16); attrlen = *ptr++; } else { attribute = *ptr++; attrlen = *ptr++; } attrlen -= 2; length -= 2; /* * This could be a Vendor-Specific attribute. * */ if ((vendorlen <= 0) && (attribute == PW_VENDOR_SPECIFIC) && (attrlen > 6)) { memcpy(&lvalue, ptr, 4); vendorcode = ntohl(lvalue); if (vendorcode != 0) { if (vendorcode == VENDORPEC_USR) { ptr += 4; memcpy(&lvalue, ptr, 4); /*printf("received USR %04x\n", ntohl(lvalue));*/ attribute = (ntohl(lvalue) & 0xFFFF) | (vendorcode << 16); ptr += 4; attrlen -= 8; length -= 8; } else { ptr += 4; vendorlen = attrlen - 4; attribute = *ptr++ | (vendorcode << 16); attrlen = *ptr++; attrlen -= 2; length -= 6; } } /* * Else the vendor wasn't found... */ } /* * FIXME: should we us paircreate() ? */ if ((pair = malloc(sizeof(VALUE_PAIR))) == NULL) { pairfree(&packet->vps); librad_log("out of memory"); errno = ENOMEM; return -1; } memset(pair, 0, sizeof(VALUE_PAIR)); if ((attr = dict_attrbyvalue(attribute)) == NULL) { snprintf(pair->name, sizeof(pair->name), "Attr-%d", attribute); pair->type = PW_TYPE_OCTETS; } else { strcpy(pair->name, attr->name); pair->type = attr->type; pair->flags = attr->flags; } pair->attribute = attribute; pair->length = attrlen; pair->operator = T_OP_EQ; pair->next = NULL; switch (pair->type) { case PW_TYPE_OCTETS: case PW_TYPE_ABINARY: case PW_TYPE_STRING: if (pair->flags.has_tag && pair->type == PW_TYPE_STRING) { int offset = 0; if ((pair->length > 0) && TAG_VALID(*ptr)) { pair->flags.tag = *ptr; pair->length--; offset = 1; } else if (pair->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) { /* * from RFC2868 - 3.5. Tunnel-Password * If the value of the Tag field is greater than * 0x00 and less than or equal to 0x1F, it SHOULD * be interpreted as indicating which tunnel * (of several alternatives) this attribute pertains; * otherwise, the Tag field SHOULD be ignored. */ pair->flags.tag = 0x00; if (pair->length > 0) pair->length--; offset = 1; } else { pair->flags.tag = 0x00; } /* * pair->length may be zero here... */ memcpy(pair->strvalue, ptr + offset, pair->length); } else { /* attrlen always < MAX_STRING_LEN */ memcpy(pair->strvalue, ptr, attrlen); pair->flags.tag = 0; } /* * FIXME: HACK for non-updated dictionaries. * REMOVE in a future release. */ if ((strcmp(pair->name, "Ascend-Send-Secret") == 0) || (strcmp(pair->name, "Ascend-Receive-Secret") == 0)) { pair->flags.encrypt = FLAG_ENCRYPT_ASCEND_SECRET; } if (pair->attribute == PW_USER_PASSWORD) { pair->flags.encrypt = FLAG_ENCRYPT_USER_PASSWORD; } /* * Decrypt passwords here. */ switch (pair->flags.encrypt) { default: break; /* * User-Password */ case FLAG_ENCRYPT_USER_PASSWORD: if (original) { rad_pwdecode((char *)pair->strvalue, pair->length, secret, (char *)original->vector); } else { rad_pwdecode((char *)pair->strvalue, pair->length, secret, (char *)packet->vector); } if (pair->attribute == PW_USER_PASSWORD) { pair->length = strlen(pair->strvalue); } break; /* * Tunnel-Password */ case FLAG_ENCRYPT_TUNNEL_PASSWORD: if (!original) { librad_log("ERROR: Tunnel-Password attribute in request: Cannot decrypt it."); return -1; } rad_tunnel_pwdecode((char *)pair->strvalue, &pair->length, secret, (char *)original->vector); break; /* * Ascend-Send-Secret * Ascend-Receive-Secret */ case FLAG_ENCRYPT_ASCEND_SECRET: { uint8_t my_digest[AUTH_VECTOR_LEN]; make_secret(my_digest, original->vector, secret, ptr); memcpy(pair->strvalue, my_digest, AUTH_VECTOR_LEN ); pair->strvalue[AUTH_VECTOR_LEN] = '\0'; pair->length = strlen(pair->strvalue); } break; } /* switch over encryption flags */ break; /* from octets/string/abinary */ case PW_TYPE_INTEGER: case PW_TYPE_DATE: case PW_TYPE_IPADDR: /* * Check for RFC compliance. If the * attribute isn't compliant, turn it * into a string of raw octets. * * Also set the lvalue to something * which should never match anything. */ if (attrlen != 4) { pair->type = PW_TYPE_OCTETS; memcpy(pair->strvalue, ptr, attrlen); pair->lvalue = 0xbad1bad1; break; } memcpy(&lvalue, ptr, 4); if (attr->type != PW_TYPE_IPADDR) { pair->lvalue = ntohl(lvalue); } else { /* * It's an IP address, keep it in network * byte order, and put the ASCII IP * address or host name into the string * value. */ pair->lvalue = lvalue; ip_ntoa(pair->strvalue, pair->lvalue); } /* * Only PW_TYPE_INTEGER should have tags. */ if (pair->flags.has_tag && pair->type == PW_TYPE_INTEGER) { pair->flags.tag = (pair->lvalue >> 24) & 0xff; pair->lvalue &= 0x00ffffff; } if (attr->type == PW_TYPE_INTEGER) { DICT_VALUE *dval; dval = dict_valbyattr(pair->attribute, pair->lvalue); if (dval) { strNcpy(pair->strvalue, dval->name, sizeof(pair->strvalue)); } } break; default: DEBUG(" %s (Unknown Type %d)\n", attr->name,attr->type); free(pair); pair = NULL; break; } if (pair) { debug_pair(pair); *tail = pair; tail = &pair->next; } ptr += attrlen; length -= attrlen; if (vendorlen > 0) vendorlen -= (attrlen + 2); }
static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, pair_lists_t list, DICT_ATTR const *da, int8_t tag, int num, bool return_null) { VALUE_PAIR *vp, *vps = NULL; RADIUS_PACKET *packet = NULL; DICT_VALUE *dv; VALUE_PAIR myvp; /* * Arg. Too much abstraction is annoying. */ switch (list) { default: if (return_null) return NULL; return vp_aprinttype(ctx, da->type); case PAIR_LIST_CONTROL: vps = request->config_items; break; case PAIR_LIST_REQUEST: packet = request->packet; if (packet) vps = packet->vps; break; case PAIR_LIST_REPLY: packet = request->reply; if (packet) vps = packet->vps; break; #ifdef WITH_PROXY case PAIR_LIST_PROXY_REQUEST: packet = request->proxy; if (packet) vps = packet->vps; break; case PAIR_LIST_PROXY_REPLY: packet = request->proxy_reply; if (packet) vps = packet->vps; break; #endif #ifdef WITH_COA case PAIR_LIST_COA: case PAIR_LIST_DM: if (request->coa) packet = request->coa->packet; if (packet) vps = packet->vps; break; case PAIR_LIST_COA_REPLY: case PAIR_LIST_DM_REPLY: if (request->coa) packet = request->coa->reply; if (packet) vps = packet->vps; break; #endif } /* * Now that we have the list, etc. handled, * find the VP and print it. */ if ((da->vendor != 0) || (da->attr < 256) || (list == PAIR_LIST_CONTROL)) { print_vp: vp = pairfind(vps, da->attr, da->vendor, tag); if (!vp) { return NULL; } goto do_print; } /* * Some non-packet expansions */ switch (da->attr) { default: break; /* ignore them */ case PW_CLIENT_SHORTNAME: if (request->client && request->client->shortname) { return talloc_strdup(ctx, request->client->shortname); } return talloc_strdup(ctx, "<UNKNOWN-CLIENT>"); case PW_REQUEST_PROCESSING_STAGE: if (request->component) { return talloc_strdup(ctx, request->component); } return talloc_strdup(ctx, "server_core"); case PW_VIRTUAL_SERVER: if (!request->server) return NULL; return talloc_strdup(ctx, request->server); case PW_MODULE_RETURN_CODE: return talloc_asprintf(ctx, "%d", request->simul_max); /* hack */ } /* * All of the attributes must now refer to a packet. If * there's no packet, we can't print any attribute * referencing it. */ if (!packet) { if (return_null) return NULL; return vp_aprinttype(ctx, da->type); } memset(&myvp, 0, sizeof(myvp)); myvp.da = da; vp = NULL; switch (da->attr) { default: goto print_vp; case PW_PACKET_TYPE: dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code); if (dv) return talloc_strdup(ctx, dv->name); return talloc_asprintf(ctx, "%d", packet->code); case PW_RESPONSE_PACKET_TYPE: { int code = 0; #ifdef WITH_PROXY if (request->proxy_reply && (!request->reply || !request->reply->code)) { code = request->proxy_reply->code; } else #endif if (request->reply) { code = request->reply->code; } return talloc_strdup(ctx, fr_packet_codes[code]); } case PW_PACKET_AUTHENTICATION_VECTOR: myvp.length = sizeof(packet->vector); memcpy(&myvp.vp_octets, packet->vector, sizeof(packet->vector)); vp = &myvp; break; case PW_CLIENT_IP_ADDRESS: case PW_PACKET_SRC_IP_ADDRESS: if (packet->src_ipaddr.af == AF_INET) { myvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr; vp = &myvp; } break; case PW_PACKET_DST_IP_ADDRESS: if (packet->dst_ipaddr.af == AF_INET) { myvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; vp = &myvp; } break; case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af == AF_INET6) { memcpy(&myvp.vp_ipv6addr, &packet->src_ipaddr.ipaddr.ip6addr, sizeof(packet->src_ipaddr.ipaddr.ip6addr)); vp = &myvp; } break; case PW_PACKET_DST_IPV6_ADDRESS: if (packet->dst_ipaddr.af == AF_INET6) { memcpy(&myvp.vp_ipv6addr, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); vp = &myvp; } break; case PW_PACKET_SRC_PORT: myvp.vp_integer = packet->src_port; vp = &myvp; break; case PW_PACKET_DST_PORT: myvp.vp_integer = packet->dst_port; vp = &myvp; break; } do_print: /* * Hack up the virtual attributes. */ if (num && (vp == &myvp)) { char *p, *q; /* * [*] means only one. */ if (num == 65537) num = 0; /* * [n] means NULL, as there's only one. */ if ((num > 0) && (num < 65536)) { return NULL; } p = vp_aprint(ctx, vp); rad_assert(p != NULL); /* * Get the length of it. */ if (num == 65536) { q = talloc_asprintf(ctx, "%d", (int) strlen(p)); talloc_free(p); return q; } return p; } /* * We want the N'th VP. */ if (num) { int count = 0; vp_cursor_t cursor; /* * Return a count of the VPs. */ if (num == 65536) { fr_cursor_init(&cursor, &vp); while (fr_cursor_next_by_num(&cursor, da->attr, da->vendor, tag) != NULL) { count++; } return talloc_asprintf(ctx, "%d", count); } /* * Ugly, but working. */ if (num == 65537) { char *p, *q; (void) fr_cursor_init(&cursor, &vp); vp = fr_cursor_next_by_num(&cursor, da->attr, da->vendor, tag); if (!vp) return NULL; p = vp_aprint(ctx, vp); while ((vp = fr_cursor_next_by_num(&cursor, da->attr, da->vendor, tag)) != NULL) { q = vp_aprint(ctx, vp); p = talloc_strdup_append(p, ","); p = talloc_strdup_append(p, q); } return p; } (void) fr_cursor_init(&cursor, &vp); while ((vp = fr_cursor_next_by_num(&cursor, da->attr, da->vendor, tag)) != NULL) { if (count == num) { break; } count++; } } if (!vp) { if (return_null) return NULL; return vp_aprinttype(ctx, da->type); } return vp_aprint(ctx, vp); }
static int dhcp_process(REQUEST *request) { int rcode; VALUE_PAIR *vp; vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer); DEBUG("Trying sub-section dhcp %s {...}", dv->name ? dv->name : "<unknown>"); rcode = module_post_auth(vp->vp_integer, request); } else { DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!"); rcode = RLM_MODULE_FAIL; } /* * Look for Relay attribute, and forward it if necessary. */ vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR); if (vp) { VALUE_PAIR *giaddr; RADIUS_PACKET relayed; request->reply->code = 0; /* don't reply to the client */ /* * Find the original giaddr. * FIXME: Maybe look in the original packet? * * It's invalid to have giaddr=0 AND a relay option */ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR); if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY))) { if (pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR)) { RDEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet"); return 1; } /* * FIXME: Add cache by XID. */ RDEBUG("DHCP: Cannot yet relay packets with giaddr = 0"); return 1; } if (request->packet->data[3] > 10) { RDEBUG("DHCP: Number of hops is greater than 10: not relaying"); return 1; } /* * Forward it VERBATIM to the next server, rather * than to the client. */ memcpy(&relayed, request->packet, sizeof(relayed)); relayed.dst_ipaddr.af = AF_INET; relayed.dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; relayed.dst_port = request->packet->dst_port; relayed.src_ipaddr = request->packet->dst_ipaddr; relayed.src_port = request->packet->dst_port; relayed.data = rad_malloc(relayed.data_len); memcpy(relayed.data, request->packet->data, request->packet->data_len); relayed.vps = NULL; /* * The only field that changes is the number of hops */ relayed.data[3]++; /* number of hops */ /* * Forward the relayed packet VERBATIM, don't * respond to the client, and forget completely * about this request. */ fr_dhcp_send(&relayed); free(relayed.data); return 1; } vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { request->reply->code = vp->vp_integer; if ((request->reply->code != 0) && (request->reply->code < PW_DHCP_OFFSET)) { request->reply->code += PW_DHCP_OFFSET; } } else switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = PW_DHCP_OFFER; break; } else if (request->packet->code == PW_DHCP_REQUEST) { request->reply->code = PW_DHCP_ACK; break; } request->reply->code = PW_DHCP_NAK; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = 0; /* ignore the packet */ } else { request->reply->code = PW_DHCP_NAK; } break; case RLM_MODULE_HANDLED: break; } /* * Releases don't get replies. */ if (request->packet->code == PW_DHCP_RELEASE) { request->reply->code = 0; } return 1; }