/* * Store logins in the RADIUS utmp file. */ static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) { rlm_rcode_t rcode = RLM_MODULE_OK; struct radutmp ut, u; vp_cursor_t cursor; VALUE_PAIR *vp; int status = -1; int protocol = -1; time_t t; int fd = -1; int port_seen = 0; int off; rlm_radutmp_t *inst = instance; char ip_name[32]; /* 255.255.255.255 */ char const *nas; NAS_PORT *cache; int r; char *filename = NULL; char *expanded = NULL; if (request->packet->src_ipaddr.af != AF_INET) { DEBUG("rlm_radutmp: IPv6 not supported!"); return RLM_MODULE_NOOP; } /* * Which type is this. */ if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) { RDEBUG("No Accounting-Status-Type record."); return RLM_MODULE_NOOP; } status = vp->vp_integer; /* * Look for weird reboot packets. * * ComOS (up to and including 3.5.1b20) does not send * standard PW_STATUS_ACCOUNTING_XXX messages. * * Check for: o no Acct-Session-Time, or time of 0 * o Acct-Session-Id of "00000000". * * We could also check for NAS-Port, that attribute * should NOT be present (but we don't right now). */ if ((status != PW_STATUS_ACCOUNTING_ON) && (status != PW_STATUS_ACCOUNTING_OFF)) do { int check1 = 0; int check2 = 0; if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY)) == NULL || vp->vp_date == 0) check1 = 1; if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID, 0, TAG_ANY)) != NULL && vp->length == 8 && memcmp(vp->vp_strvalue, "00000000", 8) == 0) check2 = 1; if (check1 == 0 || check2 == 0) { break; } INFO("rlm_radutmp: converting reboot records."); if (status == PW_STATUS_STOP) status = PW_STATUS_ACCOUNTING_OFF; if (status == PW_STATUS_START) status = PW_STATUS_ACCOUNTING_ON; } while(0); time(&t); memset(&ut, 0, sizeof(ut)); ut.porttype = 'A'; ut.nas_address = htonl(INADDR_NONE); /* * First, find the interesting attributes. */ for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) { if (!vp->da->vendor) switch (vp->da->attr) { case PW_LOGIN_IP_HOST: case PW_FRAMED_IP_ADDRESS: ut.framed_address = vp->vp_ipaddr; break; case PW_FRAMED_PROTOCOL: protocol = vp->vp_integer; break; case PW_NAS_IP_ADDRESS: ut.nas_address = vp->vp_ipaddr; break; case PW_NAS_PORT: ut.nas_port = vp->vp_integer; port_seen = 1; break; case PW_ACCT_DELAY_TIME: ut.delay = vp->vp_integer; break; case PW_ACCT_SESSION_ID: /* * If length > 8, only store the * last 8 bytes. */ off = vp->length - sizeof(ut.session_id); /* * Ascend is br0ken - it adds a \0 * to the end of any string. * Compensate. */ if (vp->length > 0 && vp->vp_strvalue[vp->length - 1] == 0) off--; if (off < 0) off = 0; memcpy(ut.session_id, vp->vp_strvalue + off, sizeof(ut.session_id)); break; case PW_NAS_PORT_TYPE: if (vp->vp_integer <= 4) ut.porttype = porttypes[vp->vp_integer]; break; case PW_CALLING_STATION_ID: if(inst->caller_id_ok) strlcpy(ut.caller_id, vp->vp_strvalue, sizeof(ut.caller_id)); break; } } /* * If we didn't find out the NAS address, use the * originator's IP address. */ if (ut.nas_address == htonl(INADDR_NONE)) { ut.nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr; nas = request->client->shortname; } else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr == ut.nas_address) { /* might be a client, might not be. */ nas = request->client->shortname; } else { /* * The NAS isn't a client, it's behind * a proxy server. In that case, just * get the IP address. */ nas = ip_ntoa(ip_name, ut.nas_address); } /* * Set the protocol field. */ if (protocol == PW_PPP) { ut.proto = 'P'; } else if (protocol == PW_SLIP) { ut.proto = 'S'; } else { ut.proto = 'T'; } ut.time = t - ut.delay; /* * Get the utmp filename, via xlat. */ filename = NULL; if (radius_axlat(&filename, request, inst->filename, NULL, NULL) < 0) { return RLM_MODULE_FAIL; } /* * See if this was a reboot. * * Hmm... we may not want to zap all of the users when the NAS comes up, because of issues with receiving * UDP packets out of order. */ if (status == PW_STATUS_ACCOUNTING_ON && (ut.nas_address != htonl(INADDR_NONE))) { RIDEBUG("NAS %s restarted (Accounting-On packet seen)", nas); rcode = radutmp_zap(request, filename, ut.nas_address, ut.time); goto finish; } if (status == PW_STATUS_ACCOUNTING_OFF && (ut.nas_address != htonl(INADDR_NONE))) { RIDEBUG("NAS %s rebooted (Accounting-Off packet seen)", nas); rcode = radutmp_zap(request, filename, ut.nas_address, ut.time); goto finish; } /* * If we don't know this type of entry pretend we succeeded. */ if (status != PW_STATUS_START && status != PW_STATUS_STOP && status != PW_STATUS_ALIVE) { REDEBUG("NAS %s port %u unknown packet type %d)", nas, ut.nas_port, status); rcode = RLM_MODULE_NOOP; goto finish; } /* * Translate the User-Name attribute, or whatever else they told us to use. */ if (radius_axlat(&expanded, request, inst->username, NULL, NULL) < 0) { rcode = RLM_MODULE_FAIL; goto finish; } strlcpy(ut.login, expanded, RUT_NAMESIZE); TALLOC_FREE(expanded); /* * Perhaps we don't want to store this record into * radutmp. We skip records: * * - without a NAS-Port (telnet / tcp access) * - with the username "!root" (console admin login) */ if (!port_seen) { RWDEBUG2("No NAS-Port seen. Cannot do anything. Checkrad will probably not work!"); rcode = RLM_MODULE_NOOP; goto finish; } if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) { RDEBUG2("Not recording administrative user"); rcode = RLM_MODULE_NOOP; goto finish; } /* * Enter into the radutmp file. */ fd = open(filename, O_RDWR|O_CREAT, inst->permission); if (fd < 0) { REDEBUG("Error accessing file %s: %s", filename, strerror(errno)); rcode = RLM_MODULE_FAIL; goto finish; } /* * Lock the utmp file, prefer lockf() over flock(). */ rad_lockfd(fd, LOCK_LEN); /* * Find the entry for this NAS / portno combination. */ if ((cache = nas_port_find(inst->nas_port_list, ut.nas_address, ut.nas_port)) != NULL) { lseek(fd, (off_t)cache->offset, SEEK_SET); } r = 0; off = 0; while (read(fd, &u, sizeof(u)) == sizeof(u)) { off += sizeof(u); if ((u.nas_address != ut.nas_address) || (u.nas_port != ut.nas_port)) { continue; } /* * Don't compare stop records to unused entries. */ if (status == PW_STATUS_STOP && u.type == P_IDLE) { continue; } if ((status == PW_STATUS_STOP) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) != 0) { /* * Don't complain if this is not a * login record (some clients can * send _only_ logout records). */ if (u.type == P_LOGIN) { RWDEBUG("Logout entry for NAS %s port %u has wrong ID", nas, u.nas_port); } r = -1; break; } if ((status == PW_STATUS_START) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0 && u.time >= ut.time) { if (u.type == P_LOGIN) { INFO("rlm_radutmp: Login entry for NAS %s port %u duplicate", nas, u.nas_port); r = -1; break; } RWDEBUG("Login entry for NAS %s port %u wrong order", nas, u.nas_port); r = -1; break; } /* * FIXME: the ALIVE record could need some more checking, but anyway I'd * rather rewrite this mess -- miquels. */ if ((status == PW_STATUS_ALIVE) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0 && u.type == P_LOGIN) { /* * Keep the original login time. */ ut.time = u.time; } if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) { RWDEBUG("negative lseek!"); lseek(fd, (off_t)0, SEEK_SET); off = 0; } else { off -= sizeof(u); } r = 1; break; } /* read the file until we find a match */ /* * Found the entry, do start/update it with * the information from the packet. */ if ((r >= 0) && (status == PW_STATUS_START || status == PW_STATUS_ALIVE)) { /* * Remember where the entry was, because it's * easier than searching through the entire file. */ if (!cache) { cache = talloc_zero(inst, NAS_PORT); if (cache) { cache->nasaddr = ut.nas_address; cache->port = ut.nas_port; cache->offset = off; cache->next = inst->nas_port_list; inst->nas_port_list = cache; } } ut.type = P_LOGIN; if (write(fd, &ut, sizeof(u)) < 0) { REDEBUG("Failed writing: %s", strerror(errno)); rcode = RLM_MODULE_FAIL; goto finish; } } /* * The user has logged off, delete the entry by * re-writing it in place. */ if (status == PW_STATUS_STOP) { if (r > 0) { u.type = P_IDLE; u.time = ut.time; u.delay = ut.delay; if (write(fd, &u, sizeof(u)) < 0) { REDEBUG("Failed writing: %s", strerror(errno)); rcode = RLM_MODULE_FAIL; goto finish; } } else if (r == 0) { RWDEBUG("Logout for NAS %s port %u, but no Login record", nas, ut.nas_port); } } finish: talloc_free(filename); if (fd > -1) { close(fd); /* and implicitely release the locks */ } return rcode; }
/** * @brief Parses the MS-SOH type/value (note: NOT type/length/value) data and * update the sohvp list * * See section 2.2.4 of MS-SOH. Because there's no "length" field we CANNOT just skip * unknown types; we need to know their length ahead of time. Therefore, we abort * if we find an unknown type. Note that sohvp may still have been modified in the * failure case. * * @param request Current request * @param p binary blob * @param data_len length of blob * @return 1 on success, 0 on failure */ static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len) { VALUE_PAIR *vp; uint8_t c; int t; char *q; while (data_len > 0) { c = *p++; data_len--; switch (c) { case 1: /* MS-Machine-Inventory-Packet * MS-SOH section 2.2.4.1 */ if (data_len < 18) { RDEBUG("insufficient data for MS-Machine-Inventory-Packet"); return 0; } data_len -= 18; vp = pairmake_packet("SoH-MS-Machine-OS-vendor", "Microsoft", T_OP_EQ); if (!vp) return 0; vp = pairmake_packet("SoH-MS-Machine-OS-version", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_32(p); p+=4; vp = pairmake_packet("SoH-MS-Machine-OS-release", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_32(p); p+=4; vp = pairmake_packet("SoH-MS-Machine-OS-build", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_32(p); p+=4; vp = pairmake_packet("SoH-MS-Machine-SP-version", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_16(p); p+=2; vp = pairmake_packet("SoH-MS-Machine-SP-release", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_16(p); p+=2; vp = pairmake_packet("SoH-MS-Machine-Processor", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = soh_pull_be_16(p); p+=2; break; case 2: /* MS-Quarantine-State - FIXME: currently unhandled * MS-SOH 2.2.4.1 * * 1 byte reserved * 1 byte flags * 8 bytes NT Time field (100-nanosec since 1 Jan 1601) * 2 byte urilen * N bytes uri */ p += 10; t = soh_pull_be_16(p); /* t == uri len */ p += 2; p += t; data_len -= 12 + t; break; case 3: /* MS-Packet-Info * MS-SOH 2.2.4.3 */ RDEBUG3("SoH MS-Packet-Info %s vers=%i", *p & 0x10 ? "request" : "response", *p & 0xf); p++; data_len--; break; case 4: /* MS-SystemGenerated-Ids - FIXME: currently unhandled * MS-SOH 2.2.4.4 * * 2 byte length * N bytes (3 bytes IANA enterprise# + 1 byte component id#) */ t = soh_pull_be_16(p); p += 2; p += t; data_len -= 2 + t; break; case 5: /* MS-MachineName * MS-SOH 2.2.4.5 * * 1 byte namelen * N bytes name */ t = soh_pull_be_16(p); p += 2; vp = pairmake_packet("SoH-MS-Machine-Name", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_strvalue = q = talloc_array(vp, char, t); vp->type = VT_DATA; memcpy(q, p, t); q[t] = 0; p += t; data_len -= 2 + t; break; case 6: /* MS-CorrelationId * MS-SOH 2.2.4.6 * * 24 bytes opaque binary which we might, in future, have * to echo back to the client in a final SoHR */ vp = pairmake_packet("SoH-MS-Correlation-Id", NULL, T_OP_EQ); if (!vp) return 0; pairmemcpy(vp, p, 24); p += 24; data_len -= 24; break; case 7: /* MS-Installed-Shvs - FIXME: currently unhandled * MS-SOH 2.2.4.7 * * 2 bytes length * N bytes (3 bytes IANA enterprise# + 1 byte component id#) */ t = soh_pull_be_16(p); p += 2; p += t; data_len -= 2 + t; break; case 8: /* MS-Machine-Inventory-Ex * MS-SOH 2.2.4.8 * * 4 bytes reserved * 1 byte product type (client=1 domain_controller=2 server=3) */ p += 4; vp = pairmake_packet("SoH-MS-Machine-Role", NULL, T_OP_EQ); if (!vp) return 0; vp->vp_integer = *p; p++; data_len -= 5; break; default: RDEBUG("SoH Unknown MS TV %i stopping", c); return 0; } } return 1; }
/* * Authenticate the user with the given password. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request) { rlm_smsotp_t *inst = instance; VALUE_PAIR *state; int bufsize; int *fdp; rlm_rcode_t rcode = RLM_MODULE_FAIL; char buffer[1000]; char output[1000]; fdp = fr_connection_get(inst->pool); if (!fdp) return RLM_MODULE_FAIL; /* Get greeting */ bufsize = read_all(fdp, buffer, sizeof(buffer)); if (bufsize <= 0) { REDEBUG("Failed reading from socket"); goto done; } /* * Look for the 'state' attribute. */ #define WRITE_ALL(_a,_b,_c) if (write_all(_a,_b,_c) < 0) goto done; state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY); if (state) { RDEBUG("Found reply to access challenge"); /* send username */ snprintf(output, sizeof(output), "check otp for %s\n", request->username->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* send password */ snprintf(output, sizeof(output), "user otp is %s\n", request->password->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* set uuid */ snprintf(output, sizeof(output), "otp id is %s\n", state->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* now check the otp */ WRITE_ALL(fdp, "get check result\n", 17); (void) read_all(fdp, buffer, sizeof(buffer)); /* end the sesssion */ WRITE_ALL(fdp, "quit\n", 5); RDEBUG("answer is %s", buffer); if (strcmp(buffer,"OK") == 0) { rcode = RLM_MODULE_OK; } goto done; } RDEBUG("Generating OTP"); /* set username */ snprintf(output, sizeof(output), "generate otp for %s\n", request->username->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* end the sesssion */ WRITE_ALL(fdp, "quit\n", 5); RDEBUG("Unique ID is %s", buffer); /* check the return string */ if (strcmp(buffer,"FAILED") == 0) { /* smsotp script returns a error */ goto done; } /* * Create the challenge, and add it to the reply. */ pair_make_reply("Reply-Message", inst->challenge, T_OP_EQ); pair_make_reply("State", buffer, T_OP_EQ); /* * Mark the packet as an Access-Challenge packet. * * The server will take care of sending it to the user. */ request->reply->code = PW_CODE_ACCESS_CHALLENGE; DEBUG("rlm_smsotp: Sending Access-Challenge"); rcode = RLM_MODULE_HANDLED; done: fr_connection_release(inst->pool, fdp); return rcode; }
/* * Allocate an IP number from the pool. */ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request) { rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance; char allocation[MAX_STRING_LEN]; int allocation_len; uint32_t ip_allocation; VALUE_PAIR *vp; rlm_sql_handle_t *handle; fr_ipaddr_t ipaddr; time_t now; /* * If there is a Framed-IP-Address attribute in the reply do nothing */ if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY) != NULL) { RDEBUG("Framed-IP-Address already exists"); return do_logging(request, inst->log_exists, RLM_MODULE_NOOP); } if (pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY) == NULL) { RDEBUG("No Pool-Name defined"); return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP); } handle = inst->sql_inst->sql_get_socket(inst->sql_inst); if (!handle) { REDEBUG("cannot get sql connection"); return RLM_MODULE_FAIL; } if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) { return RLM_MODULE_FAIL; } /* * Limit the number of clears we do. There are minor * race conditions for the check, but so what. The * actual work is protected by a transaction. The idea * here is that if we're allocating 100 IPs a second, * we're only do 1 CLEAR per second. */ now = time(NULL); if (inst->last_clear < now) { inst->last_clear = now; DO(allocate_begin); DO(allocate_clear); DO(allocate_commit); } DO(allocate_begin); allocation_len = sqlippool_query1(allocation, sizeof(allocation), inst->allocate_find, handle, inst, request, (char *) NULL, 0); /* * Nothing found... */ if (allocation_len == 0) { DO(allocate_commit); /* *Should we perform pool-check ? */ if (inst->pool_check && *inst->pool_check) { /* *Ok, so the allocate-find query found nothing ... *Let's check if the pool exists at all */ allocation_len = sqlippool_query1(allocation, sizeof(allocation), inst->pool_check, handle, inst, request, (char *) NULL, 0); inst->sql_inst->sql_release_socket(inst->sql_inst, handle); if (allocation_len) { /* * Pool exists after all... So, * the failure to allocate the IP * address was most likely due to * the depletion of the pool. In * that case, we should return * NOTFOUND */ RDEBUG("pool appears to be full"); return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND); } /* * Pool doesn't exist in the table. It * may be handled by some other instance of * sqlippool, so we should just ignore this * allocation failure and return NOOP */ RDEBUG("IP address could not be allocated as no pool exists with that name"); return RLM_MODULE_NOOP; } inst->sql_inst->sql_release_socket(inst->sql_inst, handle); RDEBUG("IP address could not be allocated"); return do_logging(request, inst->log_failed, RLM_MODULE_NOOP); } /* * FIXME: Make it work with the ipv6 addresses */ if ((ip_hton(&ipaddr, AF_INET, allocation, false) < 0) || ((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE)) { DO(allocate_commit); RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation); inst->sql_inst->sql_release_socket(inst->sql_inst, handle); return do_logging(request, inst->log_failed, RLM_MODULE_NOOP); } /* * UPDATE */ sqlippool_command(inst->allocate_update, handle, inst, request, allocation, allocation_len); RDEBUG("Allocated IP %s [%08x]", allocation, ip_allocation); vp = radius_paircreate(request->reply, &request->reply->vps, PW_FRAMED_IP_ADDRESS, 0); vp->vp_ipaddr = ip_allocation; vp->length = 4; DO(allocate_commit); inst->sql_inst->sql_release_socket(inst->sql_inst, handle); return do_logging(request, inst->log_success, RLM_MODULE_OK); }
/** Compares check and vp by value. * * Does not call any per-attribute comparison function, but does honour * check.operator. Basically does "vp.value check.op check.value". * * @param request Current request. * @param check rvalue, and operator. * @param vp lvalue. * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check * value, -2 on error. */ int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp) { int ret = 0; /* * Check for =* and !* and return appropriately */ if (check->op == T_OP_CMP_TRUE) return 0; if (check->op == T_OP_CMP_FALSE) return 1; #ifdef HAVE_REGEX_H if (check->op == T_OP_REG_EQ) { int compare; regex_t reg; char value[1024]; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; vp_prints_value(value, sizeof(value), vp, -1); /* * Include substring matches. */ compare = regcomp(®, check->vp_strvalue, REG_EXTENDED); if (compare != 0) { char buffer[256]; regerror(compare, ®, buffer, sizeof(buffer)); RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer); return -2; } memset(&rxmatch, 0, sizeof(rxmatch)); /* regexec does not seem to initialise unused elements */ compare = regexec(®, value, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); rad_regcapture(request, compare, value, rxmatch); ret = (compare == 0) ? 0 : -1; goto finish; } if (check->op == T_OP_REG_NE) { int compare; regex_t reg; char value[1024]; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; vp_prints_value(value, sizeof(value), vp, -1); /* * Include substring matches. */ compare = regcomp(®, check->vp_strvalue, REG_EXTENDED); if (compare != 0) { char buffer[256]; regerror(compare, ®, buffer, sizeof(buffer)); RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer); return -2; } compare = regexec(®, value, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); ret = (compare != 0) ? 0 : -1; } #endif /* * Attributes must be of the same type. * * FIXME: deal with type mismatch properly if one side contain * ABINARY, OCTETS or STRING by converting the other side to * a string * */ if (vp->da->type != check->da->type) return -1; /* * Tagged attributes are equal if and only if both the * tag AND value match. */ if (check->da->flags.has_tag) { ret = ((int) vp->tag) - ((int) check->tag); goto finish; } /* * Not a regular expression, compare the types. */ switch(check->da->type) { #ifdef WITH_ASCEND_BINARY /* * Ascend binary attributes can be treated * as opaque objects, I guess... */ case PW_TYPE_ABINARY: #endif case PW_TYPE_OCTETS: if (vp->length != check->length) { ret = 1; /* NOT equal */ break; } ret = memcmp(vp->vp_strvalue, check->vp_strvalue, vp->length); break; case PW_TYPE_STRING: ret = strcmp(vp->vp_strvalue, check->vp_strvalue); break; case PW_TYPE_BYTE: case PW_TYPE_SHORT: case PW_TYPE_INTEGER: ret = vp->vp_integer - check->vp_integer; break; case PW_TYPE_INTEGER64: /* * Don't want integer overflow! */ if (vp->vp_integer64 < check->vp_integer64) { ret = -1; } else if (vp->vp_integer64 > check->vp_integer64) { ret = +1; } else { ret = 0; } break; case PW_TYPE_SIGNED: if (vp->vp_signed < check->vp_signed) { ret = -1; } else if (vp->vp_signed > check->vp_signed) { ret = +1; } else { ret = 0; } break; case PW_TYPE_DATE: ret = vp->vp_date - check->vp_date; break; case PW_TYPE_IPADDR: ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr); break; case PW_TYPE_IPV6ADDR: ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, sizeof(vp->vp_ipv6addr)); break; case PW_TYPE_IPV6PREFIX: ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix, sizeof(vp->vp_ipv6prefix)); break; case PW_TYPE_IFID: ret = memcmp(&vp->vp_ifid, &check->vp_ifid, sizeof(vp->vp_ifid)); break; default: break; } finish: if (ret > 0) { return 1; } if (ret < 0) { return -1; } return 0; }
static int redisn_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs) { REDISSOCK *redis_socket; REDIS_INST *inst = instance; char redisnusername[MAX_STRING_LEN]; REDISN_GROUPLIST *group_list, *group_list_tmp; check_pairs = check_pairs; reply_pairs = reply_pairs; request_vp = request_vp; RDEBUG("redisn_groupcmp"); if (!check || !check->vp_strvalue || !check->length){ RDEBUG("redisn_groupcmp: Illegal group name"); return 1; } if (!request){ RDEBUG("redisn_groupcmp: NULL request"); return 1; } /* * Set, escape, and check the user attr here */ if (redisn_set_user(inst, request, redisnusername, NULL) < 0) return 1; /* * Get a socket for this lookup */ redis_socket = redisn_get_socket(inst); if (redis_socket == NULL) { /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return 1; } /* * Get the list of groups this user is a member of */ if (redisn_get_grouplist(inst, redis_socket, request, &group_list) < 0) { radlog_request(L_ERR, 0, request, "Error getting group membership"); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); redisn_release_socket(inst, redis_socket); return 1; } for (group_list_tmp = group_list; group_list_tmp != NULL; group_list_tmp = group_list_tmp->next) { if (strcmp(group_list_tmp->groupname, check->vp_strvalue) == 0){ RDEBUG("redisn_groupcmp finished: User is a member of group %s", check->vp_strvalue); /* Free the grouplist */ redisn_grouplist_free(&group_list); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); redisn_release_socket(inst, redis_socket); return 0; } } /* Free the grouplist */ redisn_grouplist_free(&group_list); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); redisn_release_socket(inst,redis_socket); RDEBUG("redisn_groupcmp finished: User is NOT a member of group %s", check->vp_strvalue); return 1; }
/** Start a process * * @param cmd Command to execute. This is parsed into argv[] parts, * then each individual argv part is xlat'ed. * @param request Current reuqest * @param exec_wait set to 1 if you want to read from or write to child * @param[in,out] input_fd pointer to int, receives the stdin file. * descriptor. Set to NULL and the child will have /dev/null on stdin * @param[in,out] output_fd pinter to int, receives the stdout file * descriptor. Set to NULL and child will have /dev/null on stdout. * @param input_pairs list of value pairs - these will be put into * the environment variables of the child. * @param shell_escape values before passing them as arguments. * @return PID of the child process, -1 on error. */ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait, int *input_fd, int *output_fd, VALUE_PAIR *input_pairs, bool shell_escape) { #ifndef __MINGW32__ char *p; VALUE_PAIR *vp; int n; int to_child[2] = {-1, -1}; int from_child[2] = {-1, -1}; pid_t pid; #endif int argc; int i; char *argv[MAX_ARGV]; char argv_buf[4096]; #define MAX_ENVP 1024 char *envp[MAX_ENVP]; int envlen = 0; argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv, true, sizeof(argv_buf), argv_buf); if (argc <= 0) { RDEBUG("invalid command line '%s'.", cmd); return -1; } #ifndef NDEBUG if (debug_flag > 2) { RDEBUG3("executing cmd %s", cmd); for (i = 0; i < argc; i++) { RDEBUG3("\t[%d] %s", i, argv[i]); } } #endif #ifndef __MINGW32__ /* * Open a pipe for child/parent communication, if necessary. */ if (exec_wait) { if (input_fd) { if (pipe(to_child) != 0) { RDEBUG("Couldn't open pipe to child: %s", fr_syserror(errno)); return -1; } } if (output_fd) { if (pipe(from_child) != 0) { RDEBUG("Couldn't open pipe from child: %s", fr_syserror(errno)); /* safe because these either need closing or are == -1 */ close(to_child[0]); close(to_child[1]); return -1; } } } envp[0] = NULL; if (input_pairs) { vp_cursor_t cursor; char buffer[1024]; /* * Set up the environment variables in the * parent, so we don't call libc functions that * hold mutexes. They might be locked when we fork, * and will remain locked in the child. */ for (vp = fr_cursor_init(&cursor, &input_pairs); vp; vp = fr_cursor_next(&cursor)) { /* * Hmm... maybe we shouldn't pass the * user's password in an environment * variable... */ snprintf(buffer, sizeof(buffer), "%s=", vp->da->name); if (shell_escape) { for (p = buffer; *p != '='; p++) { if (*p == '-') { *p = '_'; } else if (isalpha((int) *p)) { *p = toupper(*p); } } } n = strlen(buffer); vp_prints_value(buffer + n, sizeof(buffer) - n, vp, shell_escape ? '"' : 0); envp[envlen++] = strdup(buffer); /* * Don't add too many attributes. */ if (envlen == (MAX_ENVP - 1)) break; /* * NULL terminate for execve */ envp[envlen] = NULL; } } if (exec_wait) { pid = rad_fork(); /* remember PID */ } else { pid = fork(); /* don't wait */ } if (pid == 0) { int devnull; /* * Child process. * * We try to be fail-safe here. So if ANYTHING * goes wrong, we exit with status 1. */ /* * Open STDIN to /dev/null */ devnull = open("/dev/null", O_RDWR); if (devnull < 0) { RDEBUG("Failed opening /dev/null: %s\n", fr_syserror(errno)); /* * Where the status code is interpreted as a module rcode * one is subtracted from it, to allow 0 to equal success * * 2 is RLM_MODULE_FAIL + 1 */ exit(2); } /* * Only massage the pipe handles if the parent * has created them. */ if (exec_wait) { if (input_fd) { close(to_child[1]); dup2(to_child[0], STDIN_FILENO); } else { dup2(devnull, STDIN_FILENO); } if (output_fd) { close(from_child[0]); dup2(from_child[1], STDOUT_FILENO); } else { dup2(devnull, STDOUT_FILENO); } } else { /* no pipe, STDOUT should be /dev/null */ dup2(devnull, STDIN_FILENO); dup2(devnull, STDOUT_FILENO); } /* * If we're not debugging, then we can't do * anything with the error messages, so we throw * them away. * * If we are debugging, then we want the error * messages to go to the STDERR of the server. */ if (debug_flag == 0) { dup2(devnull, STDERR_FILENO); } close(devnull); /* * The server may have MANY FD's open. We don't * want to leave dangling FD's for the child process * to play funky games with, so we close them. */ closefrom(3); /* * I swear the signature for execve is wrong and should take 'char const * const argv[]'. */ execve(argv[0], argv, envp); printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */ /* * Where the status code is interpreted as a module rcode * one is subtracted from it, to allow 0 to equal success * * 2 is RLM_MODULE_FAIL + 1 */ exit(2); } /* * Free child environment variables */ for (i = 0; i < envlen; i++) { free(envp[i]); } /* * Parent process. */ if (pid < 0) { RDEBUG("Couldn't fork %s: %s", argv[0], fr_syserror(errno)); if (exec_wait) { /* safe because these either need closing or are == -1 */ close(to_child[0]); close(to_child[1]); close(from_child[0]); close(from_child[1]); } return -1; } /* * We're not waiting, exit, and ignore any child's status. */ if (exec_wait) { /* * Close the ends of the pipe(s) the child is using * return the ends of the pipe(s) our caller wants * */ if (input_fd) { *input_fd = to_child[1]; close(to_child[0]); } if (output_fd) { *output_fd = from_child[0]; close(from_child[1]); } } return pid; #else if (exec_wait) { RDEBUG("Wait is not supported"); return -1; } { /* * The _spawn and _exec families of functions are * found in Windows compiler libraries for * portability from UNIX. There is a variety of * functions, including the ability to pass * either a list or array of parameters, to * search in the PATH or otherwise, and whether * or not to pass an environment (a set of * environment variables). Using _spawn, you can * also specify whether you want the new process * to close your program (_P_OVERLAY), to wait * until the new process is finished (_P_WAIT) or * for the two to run concurrently (_P_NOWAIT). * _spawn and _exec are useful for instances in * which you have simple requirements for running * the program, don't want the overhead of the * Windows header file, or are interested * primarily in portability. */ /* * FIXME: check return code... what is it? */ _spawnve(_P_NOWAIT, argv[0], argv, envp); } return 0; #endif }
// Create a new client session. This should really check the version number. CSession2* CCentRepToolServer::NewSessionL(const TVersion&,const RMessage2&) const { RDEBUG("CentRepToolServer: CCentRepToolServer::NewSessionL"); return new (ELeave) CCentRepToolSession(); }
// A new session is being created // Cancel the shutdown timer if it was running void CCentRepToolServer::AddSession() { RDEBUG("CentRepToolServer: CPolicyEngineServer::AddSession"); ++iSessionCount; iShutdown.Cancel(); }
/* * SQL xlat function * * For selects the first value of the first column will be returned, * for inserts, updates and deletes the number of rows affected will be * returned instead. */ static ssize_t sql_xlat(void *instance, REQUEST *request, char const *query, char *out, size_t freespace) { rlm_sql_handle_t *handle = NULL; rlm_sql_row_t row; rlm_sql_t *inst = instance; ssize_t ret = 0; size_t len = 0; /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, NULL); handle = fr_connection_get(inst->pool); if (!handle) { return 0; } rlm_sql_query_log(inst, request, NULL, query); /* * If the query starts with any of the following prefixes, * then return the number of rows affected */ if ((strncasecmp(query, "insert", 6) == 0) || (strncasecmp(query, "update", 6) == 0) || (strncasecmp(query, "delete", 6) == 0)) { int numaffected; char buffer[21]; /* 64bit max is 20 decimal chars + null byte */ if (rlm_sql_query(&handle, inst, query) != RLM_SQL_OK) { char const *error = (inst->module->sql_error)(handle, inst->config); REDEBUG("SQL query failed: %s", error); ret = -1; goto finish; } numaffected = (inst->module->sql_affected_rows)(handle, inst->config); if (numaffected < 1) { RDEBUG("SQL query affected no rows"); goto finish; } /* * Don't chop the returned number if freespace is * too small. This hack is necessary because * some implementations of snprintf return the * size of the written data, and others return * the size of the data they *would* have written * if the output buffer was large enough. */ snprintf(buffer, sizeof(buffer), "%d", numaffected); len = strlen(buffer); if (len >= freespace){ RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->config->xlat_name); (inst->module->sql_finish_query)(handle, inst->config); ret = -1; goto finish; } memcpy(out, buffer, len + 1); /* we did bounds checking above */ ret = len; (inst->module->sql_finish_query)(handle, inst->config); goto finish; } /* else it's a SELECT statement */ if (rlm_sql_select_query(&handle, inst, query) != RLM_SQL_OK) { ret = -1; /* error handled by rlm_sql_select_query */ goto finish; } ret = rlm_sql_fetch_row(&row, &handle, inst); if (ret) { REDEBUG("SQL query failed"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } if (!row) { RDEBUG("SQL query returned no results"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } if (!row[0]){ RDEBUG("NULL value in first column of result"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } len = strlen(row[0]); if (len >= freespace){ RDEBUG("Insufficient string space"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } strlcpy(out, row[0], freespace); ret = len; (inst->module->sql_finish_select_query)(handle, inst->config); finish: fr_connection_release(inst->pool, handle); return ret; }
void CShutdown::RunL() { RDEBUG("CentRepToolServer timeout ... closing"); CActiveScheduler::Stop(); }
static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST * request) { rlm_rcode_t rcode = RLM_MODULE_OK; rlm_sql_handle_t *handle = NULL; rlm_sql_t *inst = instance; rlm_sql_row_t row; int check = 0; uint32_t ipno = 0; char const *call_num = NULL; VALUE_PAIR *vp; int ret; uint32_t nas_addr = 0; uint32_t nas_port = 0; char *expanded = NULL; /* If simul_count_query is not defined, we don't do any checking */ if (!inst->config->simul_count_query) return RLM_MODULE_NOOP; if ((!request->username) || (request->username->length == '\0')) { REDEBUG("Zero Length username not permitted"); return RLM_MODULE_INVALID; } if(sql_set_user(inst, request, NULL) < 0) { return RLM_MODULE_FAIL; } if (radius_axlat(&expanded, request, inst->config->simul_count_query, sql_escape_func, inst) < 0) { sql_unset_user(inst, request); return RLM_MODULE_FAIL; } /* initialize the sql socket */ handle = fr_connection_get(inst->pool); if (!handle) { talloc_free(expanded); sql_unset_user(inst, request); return RLM_MODULE_FAIL; } if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) { rcode = RLM_MODULE_FAIL; goto finish; } ret = rlm_sql_fetch_row(&row, &handle, inst); if (ret != 0) { rcode = RLM_MODULE_FAIL; goto finish; } if (!row) { rcode = RLM_MODULE_FAIL; goto finish; } request->simul_count = atoi(row[0]); (inst->module->sql_finish_select_query)(handle, inst->config); TALLOC_FREE(expanded); if (request->simul_count < request->simul_max) { rcode = RLM_MODULE_OK; goto finish; } /* * Looks like too many sessions, so let's start verifying * them, unless told to rely on count query only. */ if (!inst->config->simul_verify_query) { rcode = RLM_MODULE_OK; goto finish; } if (radius_axlat(&expanded, request, inst->config->simul_verify_query, sql_escape_func, inst) < 0) { rcode = RLM_MODULE_FAIL; goto finish; } if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) goto finish; /* * Setup some stuff, like for MPP detection. */ request->simul_count = 0; if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) { ipno = vp->vp_ipaddr; } if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) { call_num = vp->vp_strvalue; } while (rlm_sql_fetch_row(&row, &handle, inst) == 0) { if (!row) break; if (!row[2]){ RDEBUG("Cannot zap stale entry. No username present in entry"); rcode = RLM_MODULE_FAIL; goto finish; } if (!row[1]){ RDEBUG("Cannot zap stale entry. No session id in entry"); rcode = RLM_MODULE_FAIL; goto finish; } if (row[3]) { nas_addr = inet_addr(row[3]); } if (row[4]) { nas_port = atoi(row[4]); } check = rad_check_ts(nas_addr, nas_port, row[2], row[1]); if (check == 0) { /* * Stale record - zap it. */ if (inst->config->deletestalesessions == true) { uint32_t framed_addr = 0; char proto = 0; int sess_time = 0; if (row[5]) framed_addr = inet_addr(row[5]); if (row[7]){ if (strcmp(row[7], "PPP") == 0) proto = 'P'; else if (strcmp(row[7], "SLIP") == 0) proto = 'S'; } if (row[8]) sess_time = atoi(row[8]); session_zap(request, nas_addr, nas_port, row[2], row[1], framed_addr, proto, sess_time); } } else if (check == 1) { /* * User is still logged in. */ ++request->simul_count; /* * Does it look like a MPP attempt? */ if (row[5] && ipno && inet_addr(row[5]) == ipno) { request->simul_mpp = 2; } else if (row[6] && call_num && !strncmp(row[6],call_num,16)) { request->simul_mpp = 2; } } else { /* * Failed to check the terminal server for * duplicate logins: return an error. */ REDEBUG("Failed to check the terminal server for user '%s'.", row[2]); rcode = RLM_MODULE_FAIL; goto finish; } } finish: (inst->module->sql_finish_select_query)(handle, inst->config); fr_connection_release(inst->pool, handle); talloc_free(expanded); sql_unset_user(inst, request); /* * The Auth module apparently looks at request->simul_count, * not the return value of this module when deciding to deny * a call for too many sessions. */ return rcode; }
/* * Generic function for failing between a bunch of queries. * * Uses the same principle as rlm_linelog, expanding the 'reference' config * item using xlat to figure out what query it should execute. * * If the reference matches multiple config items, and a query fails or * doesn't update any rows, the next matching config item is used. * */ static int acct_redundant(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section) { rlm_rcode_t rcode = RLM_MODULE_OK; rlm_sql_handle_t *handle = NULL; int sql_ret; int numaffected = 0; CONF_ITEM *item; CONF_PAIR *pair; char const *attr = NULL; char const *value; char path[MAX_STRING_LEN]; char *p = path; char *expanded = NULL; rad_assert(section); if (section->reference[0] != '.') { *p++ = '.'; } if (radius_xlat(p, sizeof(path) - (p - path), request, section->reference, NULL, NULL) < 0) { rcode = RLM_MODULE_FAIL; goto finish; } item = cf_reference_item(NULL, section->cs, path); if (!item) { rcode = RLM_MODULE_FAIL; goto finish; } if (cf_item_is_section(item)){ REDEBUG("Sections are not supported as references"); rcode = RLM_MODULE_FAIL; goto finish; } pair = cf_itemtopair(item); attr = cf_pair_attr(pair); RDEBUG2("Using query template '%s'", attr); handle = fr_connection_get(inst->pool); if (!handle) { rcode = RLM_MODULE_FAIL; goto finish; } sql_set_user(inst, request, NULL); while (true) { value = cf_pair_value(pair); if (!value) { RDEBUG("Ignoring null query"); rcode = RLM_MODULE_NOOP; goto finish; } if (radius_axlat(&expanded, request, value, sql_escape_func, inst) < 0) { rcode = RLM_MODULE_FAIL; goto finish; } if (!*expanded) { RDEBUG("Ignoring null query"); rcode = RLM_MODULE_NOOP; talloc_free(expanded); goto finish; } rlm_sql_query_log(inst, request, section, expanded); /* * If rlm_sql_query cannot use the socket it'll try and * reconnect. Reconnecting will automatically release * the current socket, and try to select a new one. * * If we get RLM_SQL_RECONNECT it means all connections in the pool * were exhausted, and we couldn't create a new connection, * so we do not need to call fr_connection_release. */ sql_ret = rlm_sql_query(&handle, inst, expanded); TALLOC_FREE(expanded); if (sql_ret == RLM_SQL_RECONNECT) { rcode = RLM_MODULE_FAIL; goto finish; } rad_assert(handle); /* * Assume all other errors are incidental, and just meant our * operation failed and its not a client or SQL syntax error. * * @fixme We should actually be able to distinguish between key * constraint violations (which we expect) and other errors. */ if (sql_ret == RLM_SQL_OK) { numaffected = (inst->module->sql_affected_rows)(handle, inst->config); if (numaffected > 0) { break; /* A query succeeded, were done! */ } RDEBUG("No records updated"); } (inst->module->sql_finish_query)(handle, inst->config); /* * We assume all entries with the same name form a redundant * set of queries. */ pair = cf_pair_find_next(section->cs, pair, attr); if (!pair) { RDEBUG("No additional queries configured"); rcode = RLM_MODULE_NOOP; goto finish; } RDEBUG("Trying next query..."); } (inst->module->sql_finish_query)(handle, inst->config); finish: talloc_free(expanded); fr_connection_release(inst->pool, handle); sql_unset_user(inst, request); return rcode; }
static int eap_pwd_authenticate (void *arg, EAP_HANDLER *handler) { pwd_session_t *pwd_session; pwd_hdr *hdr; pwd_id_packet *id; EAP_PACKET *response; REQUEST *request, *fake; VALUE_PAIR *pw, **outvps, *vp; EAP_DS *eap_ds; int len, ret = 0; eap_pwd_t *inst = (eap_pwd_t *)arg; uint16_t offset; uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; BIGNUM *x = NULL, *y = NULL; if ((handler == NULL) || ((eap_ds = handler->eap_ds) == NULL) || (inst == NULL)) { return 0; } pwd_session = (pwd_session_t *)handler->opaque; request = handler->request; response = handler->eap_ds->response; hdr = (pwd_hdr *)response->type.data; buf = hdr->data; len = response->type.length - sizeof(pwd_hdr); /* * see if we're fragmenting, if so continue until we're done */ if (pwd_session->out_buf_pos) { if (len) { RDEBUG2("pwd got something more than an ACK for a fragment"); } return send_pwd_request(pwd_session, eap_ds); } /* * the first fragment will have a total length, make a * buffer to hold all the fragments */ if (EAP_PWD_GET_LENGTH_BIT(hdr)) { if (pwd_session->in_buf) { RDEBUG2("pwd already alloced buffer for fragments"); return 0; } pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]); if ((pwd_session->in_buf = malloc(pwd_session->in_buf_len)) == NULL) { RDEBUG2("pwd cannot malloc %d buffer to hold fragments", pwd_session->in_buf_len); return 0; } memset(pwd_session->in_buf, 0, pwd_session->in_buf_len); pwd_session->in_buf_pos = 0; buf += sizeof(uint16_t); len -= sizeof(uint16_t); } /* * all fragments, including the 1st will have the M(ore) bit set, * buffer those fragments! */ if (EAP_PWD_GET_MORE_BIT(hdr)) { rad_assert(pwd_session->in_buf != NULL); if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); pwd_session->in_buf_pos += len; /* * send back an ACK for this fragment */ exch = EAP_PWD_GET_EXCHANGE(hdr); eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.type = PW_EAP_PWD; eap_ds->request->type.length = sizeof(pwd_hdr); if ((eap_ds->request->type.data = malloc(sizeof(pwd_hdr))) == NULL) { radlog(L_ERR, "rlm_eap_pwd: fragment ACK, out of memory"); return 0; } hdr = (pwd_hdr *)eap_ds->request->type.data; EAP_PWD_SET_EXCHANGE(hdr, exch); return 1; } if (pwd_session->in_buf) { /* * the last fragment... */ if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); buf = pwd_session->in_buf; len = pwd_session->in_buf_len; } switch (pwd_session->state) { case PWD_STATE_ID_REQ: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { RDEBUG2("pwd exchange is incorrect: not ID"); return 0; } id = (pwd_id_packet *)buf; if ((id->prf != EAP_PWD_DEF_PRF) || (id->random_function != EAP_PWD_DEF_RAND_FUN) || (id->prep != EAP_PWD_PREP_NONE) || (memcmp(id->token, (char *)&pwd_session->token, 4)) || (id->group_num != ntohs(pwd_session->group_num))) { RDEBUG2("pwd id response is invalid"); return 0; } /* * we've agreed on the ciphersuite, record it... */ ptr = (uint8_t *)&pwd_session->ciphersuite; memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t)); ptr += sizeof(uint16_t); *ptr = EAP_PWD_DEF_RAND_FUN; ptr += sizeof(uint8_t); *ptr = EAP_PWD_DEF_PRF; pwd_session->peer_id_len = len - sizeof(pwd_id_packet); if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) { RDEBUG2("pwd id response is malformed"); return 0; } memcpy(pwd_session->peer_id, id->identity, pwd_session->peer_id_len); pwd_session->peer_id[pwd_session->peer_id_len] = '\0'; /* * make fake request to get the password for the usable ID */ if ((fake = request_alloc_fake(handler->request)) == NULL) { RDEBUG("pwd unable to create fake request!"); return 0; } if ((fake->username = pairmake("User-Name", "", T_OP_EQ)) == NULL) { RDEBUG("pwd unanable to create value pair for username!"); request_free(&fake); return 0; } memcpy(fake->username->vp_strvalue, pwd_session->peer_id, pwd_session->peer_id_len); fake->username->length = pwd_session->peer_id_len; fake->username->vp_strvalue[fake->username->length] = 0; if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { fake->server = vp->vp_strvalue; } else if (inst->conf->virtual_server) { fake->server = inst->conf->virtual_server; } /* else fake->server == request->server */ if ((debug_flag > 0) && fr_log_fp) { RDEBUG("Sending tunneled request"); debug_pair_list(fake->packet->vps); fprintf(fr_log_fp, "server %s {\n", (fake->server == NULL) ? "" : fake->server); } /* * Call authorization recursively, which will * get the password. */ module_authorize(0, fake); /* * Note that we don't do *anything* with the reply * attributes. */ if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "} # server %s\n", (fake->server == NULL) ? "" : fake->server); RDEBUG("Got tunneled reply code %d", fake->reply->code); debug_pair_list(fake->reply->vps); } if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) { DEBUG2("failed to find password for %s to do pwd authentication", pwd_session->peer_id); request_free(&fake); return 0; } if (compute_password_element(pwd_session, pwd_session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->conf->server_id, strlen(inst->conf->server_id), pwd_session->peer_id, strlen(pwd_session->peer_id), &pwd_session->token)) { DEBUG2("failed to obtain password element :-("); request_free(&fake); return 0; } request_free(&fake); /* * compute our scalar and element */ if (compute_scalar_element(pwd_session, inst->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { DEBUG2("server point allocation failed"); return 0; } /* * element is a point, get both coordinates: x and y */ if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group, pwd_session->my_element, x, y, inst->bnctx)) { DEBUG2("server point assignment failed"); BN_free(x); BN_free(y); return 0; } /* * construct request */ pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) + (2 * BN_num_bytes(pwd_session->prime)); if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) { radlog(L_ERR, "rlm_eap_pwd: out of memory to send commit"); return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); ptr = pwd_session->out_buf; offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x); BN_bn2bin(x, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y); BN_bn2bin(y, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar); BN_bn2bin(pwd_session->my_scalar, ptr + offset); pwd_session->state = PWD_STATE_COMMIT; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_COMMIT: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } /* * process the peer's commit and generate the shared key, k */ if (process_peer_commit(pwd_session, buf, inst->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } /* * compute our confirm blob */ if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) { radlog(L_ERR, "rlm_eap_pwd: failed to compute confirm!"); return 0; } /* * construct a response...which is just our confirm blob */ pwd_session->out_buf_len = SHA256_DIGEST_LENGTH; if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) { radlog(L_ERR, "rlm_eap_pwd: out of memory to send confirm"); return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH); pwd_session->state = PWD_STATE_CONFIRM; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_CONFIRM: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) { RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } if (compute_keys(pwd_session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; } eap_ds->request->code = PW_EAP_SUCCESS; /* * return the MSK (in halves) */ outvps = &handler->request->reply->vps; add_reply(outvps, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); add_reply(outvps, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN); ret = 1; break; default: RDEBUG2("unknown PWD state"); return 0; } /* * we processed the buffered fragments, get rid of them */ if (pwd_session->in_buf) { free(pwd_session->in_buf); pwd_session->in_buf = NULL; } return ret; }
/* * redisn xlat function. Right now only xGET are supported. Only * the first element of the SELECT result will be used. */ static int redisn_xlat(void *instance, REQUEST *request, char *fmt, char *out, size_t freespace, UNUSED RADIUS_ESCAPE_STRING func) { REDISSOCK *redis_socket=NULL; REDIS_ROW row; REDIS_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char redisnusername[MAX_STRING_LEN]; size_t ret = 0; RDEBUG("redisn_xlat"); /* * Add REDISN-User-Name attribute just in case it is needed * We could search the string fmt for REDISN-User-Name to see if this is * needed or not */ redisn_set_user(inst, request, redisnusername, NULL); /* * Do an xlat on the provided string (nice recursive operation). */ if (!radius_xlat(querystr, sizeof(querystr), fmt, request, redisn_escape_func, inst)) { radlog(L_ERR, "rlm_redisn (%s): xlat failed.", inst->xlat_name); return 0; } query_log(request, inst, querystr); redis_socket = redisn_get_socket(inst); if (redis_socket == NULL) return 0; if (rlm_redisn_query(inst, redis_socket, querystr)<0) { radlog(L_ERR, "rlm_redisn (%s): database query error, %s", inst->xlat_name,querystr); redisn_release_socket(inst,redis_socket); return 0; } ret = rlm_redisn_fetch_row(inst, redis_socket); if (ret) { RDEBUG("REDIS query did not succeed"); (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst,redis_socket); return 0; } row = redis_socket->row; if (row == NULL) { RDEBUG("REDIS query did not return any results"); (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst,redis_socket); return 0; } if (row[0] == NULL){ RDEBUG("row[0] returned NULL"); (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst,redis_socket); return 0; } ret = strlen(row[0]); if (ret >= freespace){ RDEBUG("Insufficient string space"); (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst,redis_socket); return 0; } strlcpy(out,row[0],freespace); RDEBUG("redisn_xlat finished"); (inst->redisn_finish_query)(inst,redis_socket); redisn_release_socket(inst,redis_socket); return ret; }
// A session is being destroyed // Start the shutdown timer if it is the last session. void CCentRepToolServer::DropSession() { RDEBUG("CentRepToolServer: CPolicyEngineServer::DropSession"); if (--iSessionCount==0) iShutdown.Start(); }
static rlm_rcode_t rlm_redisn_checksimul(void *instance, REQUEST * request) { REDISSOCK *redis_socket; REDIS_INST *inst = instance; REDIS_ROW row; char querystr[MAX_QUERY_LEN]; char redisnusername[MAX_STRING_LEN]; int check = 0; uint32_t ipno = 0; char *call_num = NULL; VALUE_PAIR *vp; int ret; uint32_t nas_addr = 0; int nas_port = 0; /* If simul_count_query is not defined, we don't do any checking */ if (!inst->simul_count_query || (inst->simul_count_query[0] == 0)) { return RLM_MODULE_NOOP; } if((request->username == NULL) || (request->username->length == 0)) { radlog_request(L_ERR, 0, request, "Zero Length username not permitted\n"); return RLM_MODULE_INVALID; } if(redisn_set_user(inst, request, redisnusername, NULL) < 0) return RLM_MODULE_FAIL; radius_xlat(querystr, sizeof(querystr), inst->simul_count_query, request, redisn_escape_func, inst); /* initialize the redisn socket */ redis_socket = redisn_get_socket(inst); if(redis_socket == NULL) return RLM_MODULE_FAIL; if(rlm_redisn_query(inst, redis_socket, querystr)) { radlog(L_ERR, "rlm_redisn (%s) redisn_checksimul: Database query failed", inst->xlat_name); redisn_release_socket(inst, redis_socket); return RLM_MODULE_FAIL; } ret = rlm_redisn_fetch_row(inst, redis_socket); if (ret != 0) { (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); return RLM_MODULE_FAIL; } row = redis_socket->row; if (row == NULL) { (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); return RLM_MODULE_FAIL; } request->simul_count = atoi(row[0]); (inst->redisn_finish_query)(inst, redis_socket); if(request->simul_count < request->simul_max) { redisn_release_socket(inst, redis_socket); return RLM_MODULE_OK; } /* * Looks like too many sessions, so let's start verifying * them, unless told to rely on count query only. */ if (!inst->simul_verify_query || (inst->simul_verify_query[0] == '\0')) { redisn_release_socket(inst, redis_socket); return RLM_MODULE_OK; } radius_xlat(querystr, sizeof(querystr), inst->simul_verify_query, request, redisn_escape_func, inst); if(rlm_redisn_query(inst, redis_socket, querystr)) { radlog_request(L_ERR, 0, request, "Database query error"); redisn_release_socket(inst, redis_socket); return RLM_MODULE_FAIL; } /* * Setup some stuff, like for MPP detection. */ request->simul_count = 0; if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) ipno = vp->vp_ipaddr; if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) call_num = vp->vp_strvalue; while (rlm_redisn_fetch_row(inst, redis_socket) == 0) { row = redis_socket->row; if (row == NULL) break; if (!row[2]){ (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); RDEBUG("Cannot zap stale entry. No username present in entry.", inst->xlat_name); return RLM_MODULE_FAIL; } if (!row[1]){ (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); RDEBUG("Cannot zap stale entry. No session id in entry.", inst->xlat_name); return RLM_MODULE_FAIL; } if (row[3]) nas_addr = inet_addr(row[3]); if (row[4]) nas_port = atoi(row[4]); check = rad_check_ts(nas_addr, nas_port, row[2], row[1]); if (check == 0) { /* * Stale record - zap it. */ if (inst->deletestalesessions == TRUE) { uint32_t framed_addr = 0; char proto = 0; int sess_time = 0; if (row[5]) framed_addr = inet_addr(row[5]); if (row[7]){ if (strcmp(row[7], "PPP") == 0) proto = 'P'; else if (strcmp(row[7], "SLIP") == 0) proto = 'S'; } if (row[8]) sess_time = atoi(row[8]); session_zap(request, nas_addr, nas_port, row[2], row[1], framed_addr, proto, sess_time); } } else if (check == 1) { /* * User is still logged in. */ ++request->simul_count; /* * Does it look like a MPP attempt? */ if (row[5] && ipno && inet_addr(row[5]) == ipno) request->simul_mpp = 2; else if (row[6] && call_num && !strncmp(row[6],call_num,16)) request->simul_mpp = 2; } else { /* * Failed to check the terminal server for * duplicate logins: return an error. */ (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); radlog_request(L_ERR, 0, request, "Failed to check the terminal server for user '%s'.", row[2]); return RLM_MODULE_FAIL; } } (inst->redisn_finish_query)(inst, redis_socket); redisn_release_socket(inst, redis_socket); /* * The Auth module apparently looks at request->simul_count, * not the return value of this module when deciding to deny * a call for too many sessions. */ return RLM_MODULE_OK; }
inline CCentRepToolSession::CCentRepToolSession() { RDEBUG("CentRepToolServer: CCentRepToolSession::CCentRepToolSession"); }
/** Read from the child process. * * @param request The current request. * @param fd file descriptor to read from. * @param pid pid of child, will be reaped if it dies. * @param timeout amount of time to wait, in seconds. * @param answer buffer to write into. * @param left length of buffer. * @return -1 on error, or length of output. */ int radius_readfrom_program(REQUEST *request, int fd, pid_t pid, int timeout, char *answer, int left) { int done = 0; #ifndef __MINGW32__ int status; struct timeval start; #ifdef O_NONBLOCK bool nonblock = true; #endif #ifdef O_NONBLOCK /* * Try to set it non-blocking. */ do { int flags; if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) { nonblock = false; break; } flags |= O_NONBLOCK; if( fcntl(fd, F_SETFL, flags) < 0) { nonblock = false; break; } } while (0); #endif /* * Read from the pipe until we doesn't get any more or * until the message is full. */ gettimeofday(&start, NULL); while (1) { int rcode; fd_set fds; struct timeval when, elapsed, wake; FD_ZERO(&fds); FD_SET(fd, &fds); gettimeofday(&when, NULL); tv_sub(&when, &start, &elapsed); if (elapsed.tv_sec >= timeout) goto too_long; when.tv_sec = timeout; when.tv_usec = 0; tv_sub(&when, &elapsed, &wake); rcode = select(fd + 1, &fds, NULL, NULL, &wake); if (rcode == 0) { too_long: RDEBUG("Child PID %u is taking too much time: forcing failure and killing child.", pid); kill(pid, SIGTERM); close(fd); /* should give SIGPIPE to child, too */ /* * Clean up the child entry. */ rad_waitpid(pid, &status); return -1; } if (rcode < 0) { if (errno == EINTR) continue; break; } #ifdef O_NONBLOCK /* * Read as many bytes as possible. The kernel * will return the number of bytes available. */ if (nonblock) { status = read(fd, answer + done, left); } else #endif /* * There's at least 1 byte ready: read it. */ status = read(fd, answer + done, 1); /* * Nothing more to read: stop. */ if (status == 0) { break; } /* * Error: See if we have to continue. */ if (status < 0) { /* * We were interrupted: continue reading. */ if (errno == EINTR) { continue; } /* * There was another error. Most likely * The child process has finished, and * exited. */ break; } done += status; left -= status; if (left <= 0) break; } #endif /* __MINGW32__ */ /* Strip trailing new lines */ while ((done > 0) && (answer[done - 1] == '\n')) { answer[--done] = '\0'; } return done; }
void CCentRepToolSession::DispatchMessageL(const RMessage2& aMessage) { //Subsession management switch (aMessage.Function()) { case ECreateRepositorySubSession: case ECreateCheckAccessSession: { RDEBUG("CentRepTool: New repository session"); NewRepositorySessionL( aMessage); return; } case ECloseRepositorySubSession: case ECloseCheckAcceessSession: { RDEBUG("CentRepTool: Close repository session"); DeleteRepositorySession( aMessage); return; } case ECheckCommitState : { RDEBUG("CentRepTool: Check last commit state"); CRepositorySession::CheckCommitStateL(); return; } case EPerformCentRepToolRFS : { RDEBUG("CentRepTool: Perform RFS"); PerformRFSL(); return; } } //Trusted session operations CRepositorySession * repositorySession = RepositorySessionFromHandle( aMessage); iCurrentSession = repositorySession; switch (aMessage.Function()) { case EInitRepositorySession: { RDEBUG("CentRepTool: Init repository session"); repositorySession->InitRepositorySessionL(); } break; case ESetSIDWRForSetting : { RDEBUG("CentRepTool: Add SID for individual setting"); repositorySession->SetSecurityIdForSettingL( aMessage); } break; case ESetSIDWRForRange: { RDEBUG("CentRepTool: Add SID for range"); repositorySession->SetSecurityIdForRangeL( aMessage); } break; case ERestoreSetting : { RDEBUG("CentRepTool: Restore individual setting"); repositorySession->RestoreSettingL( aMessage); } break; case ERestoreRange : { RDEBUG("CentRepTool: Restore range"); repositorySession->RestoreRangeL( aMessage); } break; case EAddSIDWRForDefaults : { RDEBUG("CentRepTool: Add SID for all settings (default, range, mask)"); repositorySession->AddSidForDefaultsL( aMessage); } break; case ERestoreDefaults : { RDEBUG("CentRepTool: "); RDEBUG("CentRepTool: Remove SID from all settings (default, range, mask)"); repositorySession->RestoreDefaultsL( aMessage); } break; case EFlushRepository : { RDEBUG("CentRepTool: Commit security changes in repository"); repositorySession->CommitRepositoryL(); } break; case ESetSIDWRForMask : { RDEBUG("CentRepTool: Set SID for mask setting"); repositorySession->SetSecurityIdForMaskL( aMessage); } break; case ERestoreMask : { RDEBUG("CentRepTool: Restore mask setting"); repositorySession->RestoreMaskL( aMessage); } break; case ERemoveBackupFlagForMask: { RDEBUG("CentRepTool: Set backup flag for mask"); repositorySession->RemoveBackupForMaskL( aMessage); } break; case ERestoreBackupFlagForMask: { RDEBUG("CentRepTool: Restore backup flag for mask"); repositorySession->RestoreMaskBackupL( aMessage); } break; case ERemoveBackupFlagForDefaults: { RDEBUG("CentRepTool: Set backup flag for defaults"); repositorySession->RemoveDefaultBackup(); } break; case ERestoreBackupFlagForDefaults: { RDEBUG("CentRepTool: Restore backup flag for defaults"); repositorySession->RestoreDefaultBackupL(); } break; case ERemoveBackupFlagForRange: { RDEBUG("CentRepTool: Set backup flag for range"); repositorySession->RemoveBackupForRangeL( aMessage); } break; case ERestoreBackupFlagForRange: { RDEBUG("CentRepTool: Restore backup flag for range"); repositorySession->RestoreRangeBackupL( aMessage); } break; case ECheckAccess: { RDEBUG("CentRepTool: Check access"); repositorySession->CheckAccessL( aMessage); } break; default: break; } }
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; }
// RMessagePtr2::Panic() also completes the message. This is: // (a) important for efficient cleanup within the kernel // (b) a problem if the message is completed a second time void PanicClient(const RMessagePtr2& aMessage, TCentRepToolServerPanic aPanic) { RDEBUG("CentRepTool PanicClient"); aMessage.Panic( IniConstants::KCentRepToolPanic,aPanic); }
/* * Check for an Accounting-Stop * If we find one and we have allocated an IP to this nas/port * combination, then deallocate it. */ static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request) { int rcode = RLM_MODULE_NOOP; VALUE_PAIR *vp; int acct_status_type; rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance; rlm_sql_handle_t *handle; 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; } acct_status_type = vp->vp_integer; switch (acct_status_type) { case PW_STATUS_START: case PW_STATUS_ALIVE: case PW_STATUS_STOP: case PW_STATUS_ACCOUNTING_ON: case PW_STATUS_ACCOUNTING_OFF: break; /* continue through to the next section */ default: /* We don't care about any other accounting packet */ return RLM_MODULE_NOOP; } handle = inst->sql_inst->sql_get_socket(inst->sql_inst); if (!handle) { RDEBUG("Cannot allocate sql connection"); return RLM_MODULE_FAIL; } if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) { return RLM_MODULE_FAIL; } switch (acct_status_type) { case PW_STATUS_START: rcode = mod_accounting_start(handle, inst, request); break; case PW_STATUS_ALIVE: rcode = mod_accounting_alive(handle, inst, request); break; case PW_STATUS_STOP: rcode = mod_accounting_stop(handle, inst, request); break; case PW_STATUS_ACCOUNTING_ON: rcode = mod_accounting_on(handle, inst, request); break; case PW_STATUS_ACCOUNTING_OFF: rcode = mod_accounting_off(handle, inst, request); break; } inst->sql_inst->sql_release_socket(inst->sql_inst, handle); return rcode; }
inline void CShutdown::Start() { RDEBUG("CentRepToolServer: starting shutdown timeout"); After(KPolicyEngineShutdownDelay); }
/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST. * * Takes a single value_pair_map_t, resolves request and list identifiers * to pointers in the current request, then attempts to retrieve module * specific value(s) using callback, and adds the resulting values to the * correct request/list. * * @param request The current request. * @param map specifying destination attribute and location and src identifier. * @param func to retrieve module specific values and convert them to * VALUE_PAIRS. * @param ctx to be passed to func. * @param src name to be used in debugging if different from map value. * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success. */ int radius_map2request(REQUEST *request, value_pair_map_t const *map, UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx) { int rcode; vp_cursor_t cursor; VALUE_PAIR **list, *vp, *head = NULL; char buffer[1024]; if (radius_request(&request, map->dst->request) < 0) { REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name); return -2; } list = radius_list(request, map->dst->list); if (!list) { REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name); return -2; } /* * The callback should either return -1 to signify operations error, -2 when it can't find the * attribute or list being referenced, or 0 to signify success. * It may return "sucess", but still have no VPs to work with. * Only if it returned an error code should it not write anything to the head pointer. */ rcode = func(&head, request, map, ctx); if (rcode < 0) { rad_assert(!head); return rcode; } if (!head) return 0; VERIFY_VP(head); if (debug_flag) for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) { char *value; switch (map->src->type) { /* * Just print the value being assigned */ default: case VPT_TYPE_LITERAL: vp_prints_value(buffer, sizeof(buffer), vp, '\''); value = buffer; break; case VPT_TYPE_XLAT: vp_prints_value(buffer, sizeof(buffer), vp, '"'); value = buffer; break; case VPT_TYPE_DATA: vp_prints_value(buffer, sizeof(buffer), vp, 0); value = buffer; break; /* * Just printing the value doesn't make sense, but we still * want to know what it was... */ case VPT_TYPE_LIST: vp_prints_value(buffer, sizeof(buffer), vp, '\''); value = talloc_asprintf(request, "&%s%s -> %s", map->src->name, vp->da->name, buffer); break; case VPT_TYPE_ATTR: vp_prints_value(buffer, sizeof(buffer), vp, '\''); value = talloc_asprintf(request, "&%s -> %s", map->src->name, buffer); break; } RDEBUG("\t\t%s %s %s", map->dst->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), value); if (value != buffer) talloc_free(value); } /* * Use pairmove so the operator is respected */ radius_pairmove(request, list, head); return 0; }
static rlm_rcode_t rlm_redisn_authorize(void *instance, REQUEST * request) { VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *user_profile = NULL; int found = 0; int dofallthrough = 1; int rows; REDISSOCK *redis_socket; REDIS_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char redisnusername[MAX_STRING_LEN]; /* * the profile username is used as the redisnusername during * profile checking so that we don't overwrite the orignal * redisnusername string */ char profileusername[MAX_STRING_LEN]; /* * Set, escape, and check the user attr here */ if (redisn_set_user(inst, request, redisnusername, NULL) < 0) return RLM_MODULE_FAIL; /* * reserve a socket */ redis_socket = redisn_get_socket(inst); if (redis_socket == NULL) { /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } /* * After this point, ALL 'return's MUST release the REDISN socket! */ /* * Alright, start by getting the specific entry for the user */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_check_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } rows = redisn_getvpdata(inst, redis_socket, &check_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); return RLM_MODULE_FAIL; } else if (rows > 0) { /* * Only do this if *some* check pairs were returned */ if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) { found = 1; RDEBUG2("User found in radcheck table"); if (inst->authorize_reply_query && *inst->authorize_reply_query) { /* * Now get the reply pairs since the paircompare matched */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_reply_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); return RLM_MODULE_FAIL; } if (redisn_getvpdata(inst, redis_socket, &reply_tmp, querystr) < 0) { radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); return RLM_MODULE_FAIL; } if (!inst->read_groups) { dofallthrough = fallthrough(reply_tmp); DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); } pairxlatmove(request, &request->reply->vps, &reply_tmp); } pairxlatmove(request, &request->config_items, &check_tmp); } } /* * Clear out the pairlists */ pairfree(&check_tmp); pairfree(&reply_tmp); /* * dofallthrough is set to 1 by default so that if the user information * is not found, we will still process groups. If the user information, * however, *is* found, Fall-Through must be set in order to process * the groups as well */ DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (dofallthrough) { rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else if (rows > 0) { found = 1; } } /* * repeat the above process with the default profile or User-Profile */ DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (dofallthrough) { int profile_found = 0; /* * Check for a default_profile or for a User-Profile. */ user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY); if (inst->default_profile[0] != 0 || user_profile != NULL){ char *profile = inst->default_profile; if (user_profile != NULL) profile = user_profile->vp_strvalue; if (profile && strlen(profile)){ RDEBUG("Checking profile %s", profile); if (redisn_set_user(inst, request, profileusername, profile) < 0) { radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else { profile_found = 1; } } } if (profile_found) { rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough); DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else if (rows > 0) { found = 1; } } } /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); redisn_release_socket(inst, redis_socket); if (!found) { RDEBUG("User %s not found", redisnusername); return RLM_MODULE_NOTFOUND; } else { return RLM_MODULE_OK; } }
/** * @brief Parse the MS-SOH response in data and update sohvp. * * Note that sohvp might still have been updated in event of a failure. * * @param request Current request * @param data MS-SOH blob * @param data_len length of MS-SOH blob * * @return 0 on success, -1 on failure * */ int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) { VALUE_PAIR *vp; eap_soh hdr; soh_response resp; soh_mode_subheader mode; soh_tlv tlv; int curr_shid=-1, curr_shid_c=-1, curr_hc=-1; rad_assert(request->packet != NULL); hdr.tlv_type = soh_pull_be_16(data); data += 2; hdr.tlv_len = soh_pull_be_16(data); data += 2; hdr.tlv_vendor = soh_pull_be_32(data); data += 4; if (hdr.tlv_type != 7 || hdr.tlv_vendor != 0x137) { RDEBUG("SoH payload is %i %08x not a ms-vendor packet", hdr.tlv_type, hdr.tlv_vendor); return -1; } hdr.soh_type = soh_pull_be_16(data); data += 2; hdr.soh_len = soh_pull_be_16(data); data += 2; if (hdr.soh_type != 1) { RDEBUG("SoH tlv %04x is not a response", hdr.soh_type); return -1; } /* FIXME: check for sufficient data */ resp.outer_type = soh_pull_be_16(data); data += 2; resp.outer_len = soh_pull_be_16(data); data += 2; resp.vendor = soh_pull_be_32(data); data += 4; resp.inner_type = soh_pull_be_16(data); data += 2; resp.inner_len = soh_pull_be_16(data); data += 2; if (resp.outer_type!=7 || resp.vendor != 0x137) { RDEBUG("SoH response outer type %i/vendor %08x not recognised", resp.outer_type, resp.vendor); return -1; } switch (resp.inner_type) { case 1: /* no mode sub-header */ RDEBUG("SoH without mode subheader"); break; case 2: mode.outer_type = soh_pull_be_16(data); data += 2; mode.outer_len = soh_pull_be_16(data); data += 2; mode.vendor = soh_pull_be_32(data); data += 4; memcpy(mode.corrid, data, 24); data += 24; mode.intent = data[0]; mode.content_type = data[1]; data += 2; if (mode.outer_type != 7 || mode.vendor != 0x137 || mode.content_type != 0) { RDEBUG3("SoH mode subheader outer type %i/vendor %08x/content type %i invalid", mode.outer_type, mode.vendor, mode.content_type); return -1; } RDEBUG3("SoH with mode subheader"); break; default: RDEBUG("SoH invalid inner type %i", resp.inner_type); return -1; } /* subtract off the relevant amount of data */ if (resp.inner_type==2) { data_len = resp.inner_len - 34; } else { data_len = resp.inner_len; } /* TLV * MS-SOH 2.2.1 * See also 2.2.3 * * 1 bit mandatory * 1 bit reserved * 14 bits tlv type * 2 bytes tlv length * N bytes payload * */ while (data_len >= 4) { tlv.tlv_type = soh_pull_be_16(data); data += 2; tlv.tlv_len = soh_pull_be_16(data); data += 2; data_len -= 4; switch (tlv.tlv_type) { case 2: /* System-Health-Id TLV * MS-SOH 2.2.3.1 * * 3 bytes IANA/SMI vendor code * 1 byte component (i.e. within vendor, which SoH component */ curr_shid = soh_pull_be_24(data); curr_shid_c = data[3]; RDEBUG2("SoH System-Health-ID vendor %08x component=%i", curr_shid, curr_shid_c); break; case 7: /* Vendor-Specific packet * MS-SOH 2.2.3.3 * * 4 bytes vendor, supposedly ignored by NAP * N bytes payload; for Microsoft component#0 this is the MS TV stuff */ if (curr_shid==0x137 && curr_shid_c==0) { RDEBUG2("SoH MS type-value payload"); eapsoh_mstlv(request, data + 4, tlv.tlv_len - 4); } else { RDEBUG2("SoH unhandled vendor-specific TLV %08x/component=%i %i bytes payload", curr_shid, curr_shid_c, tlv.tlv_len); } break; case 8: /* Health-Class * MS-SOH 2.2.3.5.6 * * 1 byte integer */ RDEBUG2("SoH Health-Class %i", data[0]); curr_hc = data[0]; break; case 9: /* Software-Version * MS-SOH 2.2.3.5.7 * * 1 byte integer */ RDEBUG2("SoH Software-Version %i", data[0]); break; case 11: /* Health-Class status * MS-SOH 2.2.3.5.9 * * variable data; for the MS System Health vendor, these are 4-byte * integers which are a really, really dumb format: * * 28 bits ignore * 1 bit - 1==product snoozed * 1 bit - 1==microsoft product * 1 bit - 1==product up-to-date * 1 bit - 1==product enabled */ RDEBUG2("SoH Health-Class-Status - current shid=%08x component=%i", curr_shid, curr_shid_c); if (curr_shid==0x137 && curr_shid_c==128) { char const *s, *t; uint32_t hcstatus = soh_pull_be_32(data); RDEBUG2("SoH Health-Class-Status microsoft DWORD=%08x", hcstatus); vp = pairmake_packet("SoH-MS-Windows-Health-Status", NULL, T_OP_EQ); if (!vp) return 0; switch (curr_hc) { case 4: /* security updates */ s = "security-updates"; switch (hcstatus) { case 0xff0005: pairsprintf(vp, "%s ok all-installed", s); break; case 0xff0006: pairsprintf(vp, "%s warn some-missing", s); break; case 0xff0008: pairsprintf(vp, "%s warn never-started", s); break; case 0xc0ff000c: pairsprintf(vp, "%s error no-wsus-srv", s); break; case 0xc0ff000d: pairsprintf(vp, "%s error no-wsus-clid", s); break; case 0xc0ff000e: pairsprintf(vp, "%s warn wsus-disabled", s); break; case 0xc0ff000f: pairsprintf(vp, "%s error comm-failure", s); break; case 0xc0ff0010: pairsprintf(vp, "%s warn needs-reboot", s); break; default: pairsprintf(vp, "%s error %08x", s, hcstatus); break; } break; case 3: /* auto updates */ s = "auto-updates"; switch (hcstatus) { case 1: pairsprintf(vp, "%s warn disabled", s); break; case 2: pairsprintf(vp, "%s ok action=check-only", s); break; case 3: pairsprintf(vp, "%s ok action=download", s); break; case 4: pairsprintf(vp, "%s ok action=install", s); break; case 5: pairsprintf(vp, "%s warn unconfigured", s); break; case 0xc0ff0003: pairsprintf(vp, "%s warn service-down", s); break; case 0xc0ff0018: pairsprintf(vp, "%s warn never-started", s); break; default: pairsprintf(vp, "%s error %08x", s, hcstatus); break; } break; default: /* other - firewall, antivirus, antispyware */ s = healthclass2str(curr_hc); if (s) { /* bah. this is vile. stupid microsoft */ if (hcstatus & 0xff000000) { /* top octet non-zero means an error * FIXME: is this always correct? MS-WSH 2.2.8 is unclear */ t = clientstatus2str(hcstatus); if (t) { pairsprintf(vp, "%s error %s", s, t); } else { pairsprintf(vp, "%s error %08x", s, hcstatus); } } else { pairsprintf(vp, "%s ok snoozed=%i microsoft=%i up2date=%i enabled=%i", s, hcstatus & 0x8 ? 1 : 0, hcstatus & 0x4 ? 1 : 0, hcstatus & 0x2 ? 1 : 0, hcstatus & 0x1 ? 1 : 0 ); } } else { pairsprintf(vp, "%i unknown %08x", curr_hc, hcstatus); } break; } } else { vp = pairmake_packet("SoH-MS-Health-Other", NULL, T_OP_EQ); if (!vp) return 0; /* FIXME: what to do with the payload? */ pairsprintf(vp, "%08x/%i ?", curr_shid, curr_shid_c); } break; default: RDEBUG("SoH Unknown TLV %i len=%i", tlv.tlv_type, tlv.tlv_len); break; } data += tlv.tlv_len; data_len -= tlv.tlv_len; } return 0; }
/* * Accounting: save the account data to our redisn table */ static rlm_rcode_t rlm_redisn_accounting(void *instance, REQUEST * request) { REDISSOCK *redis_socket = NULL; VALUE_PAIR *pair; REDIS_INST *inst = instance; int ret = RLM_MODULE_OK; int acctstatustype = 0; char logstr[MAX_QUERY_LEN]; char redisnusername[MAX_STRING_LEN]; char** queries=NULL; /* * Find the Acct Status Type */ if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL) { acctstatustype = pair->vp_integer; } else { radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL, inst); radlog_request(L_ERR, 0, request, "%s", logstr); return RLM_MODULE_INVALID; } switch (acctstatustype) { /* * The Terminal server informed us that it was rebooted * STOP all records from this NAS */ case PW_STATUS_ACCOUNTING_ON: RDEBUG("Received Acct On packet"); queries=inst->accounting_on_queries; break; case PW_STATUS_ACCOUNTING_OFF: RDEBUG("Received Acct Off packet"); queries=inst->accounting_off_queries; break; case PW_STATUS_START: RDEBUG("Received Acct Start packet"); queries=inst->accounting_start_queries; break; case PW_STATUS_STOP: RDEBUG("Received Acct Stop packet"); #if 0 //#ifdef CISCO_ACCOUNTING_HACK { /* * If stop but zero session length AND no previous * session found, drop it as in invalid packet * This is to fix CISCO's aaa from filling our * table with bogus crap */ int acctsessiontime = 0; if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY)) != NULL) acctsessiontime = pair->vp_integer; if (acctsessiontime <= 0) { radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL, inst); radlog_request(L_DBG, 0, request, "%s", logstr); redisn_release_socket(inst, redis_socket); return RLM_MODULE_NOOP; } } #endif queries=inst->accounting_stop_queries; break; case PW_STATUS_ALIVE: RDEBUG("Received Acct Alive packet"); queries=inst->accounting_update_queries; break; /* * Anything else is ignored. */ default: RDEBUG("Unsupported Acct-Status-Type = %d", acctstatustype); return RLM_MODULE_NOOP; break; } if (queries==NULL ||*queries==NULL) ret=RLM_MODULE_NOOP; else { char querystr[MAX_QUERY_LEN]; redis_socket = redisn_get_socket(inst); if (redis_socket == NULL) return(RLM_MODULE_FAIL); redisn_set_user(inst, request, redisnusername, NULL); while(*queries) { char* query=*queries; memset(querystr, 0, MAX_QUERY_LEN); radius_xlat(querystr, sizeof(querystr), query, request, redisn_escape_func, inst); query_log(request, inst, querystr); if (rlm_redisn_query(inst, redis_socket, querystr)) { radlog_request(L_ERR, 0, request, "Accounting query failed: %s", querystr); ret = RLM_MODULE_FAIL; } (inst->redisn_finish_query)(inst, redis_socket); queries++; } redisn_release_socket(inst, redis_socket); } return ret; }
/* * The xlat function */ static ssize_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace) { rlm_perl_t *inst = (rlm_perl_t *) instance; char *tmp; char const *p, *q; int count; size_t ret = 0; STRLEN n_a; #ifdef USE_ITHREADS PerlInterpreter *interp; pthread_mutex_lock(&inst->clone_mutex); interp = rlm_perl_clone(inst->perl, inst->thread_key); { dTHXa(interp); PERL_SET_CONTEXT(interp); } pthread_mutex_unlock(&inst->clone_mutex); #else PERL_SET_CONTEXT(inst->perl); #endif { dSP; ENTER;SAVETMPS; PUSHMARK(SP); p = q = fmt; while (*p == ' ') { p++; q++; } while (*q) { if (*q == ' ') { XPUSHs(sv_2mortal(newSVpvn(p, q - p))); p = q + 1; /* * Don't use an empty string */ while (*p == ' ') p++; q = p; } q++; } /* * And the last bit. */ if (*p) { XPUSHs(sv_2mortal(newSVpvn(p, strlen(p)))); } PUTBACK; count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL); SPAGAIN; if (SvTRUE(ERRSV)) { REDEBUG("Exit %s", SvPV(ERRSV,n_a)); (void)POPs; } else if (count > 0) { tmp = POPp; strlcpy(out, tmp, freespace); ret = strlen(out); RDEBUG("Len is %zu , out is %s freespace is %zu", ret, out, freespace); } PUTBACK ; FREETMPS ; LEAVE ; } return ret; }
/* * %{poke:sql.foo=bar} */ static ssize_t xlat_poke(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) { int i; void *data, *base; char *p, *q; module_instance_t *mi; char *buffer; CONF_SECTION *modules; CONF_PAIR *cp; CONF_PARSER const *variables; size_t len; rad_assert(outlen > 1); rad_assert(request != NULL); rad_assert(fmt != NULL); rad_assert(out != NULL); rad_assert(*out); modules = cf_section_sub_find(request->root->config, "modules"); if (!modules) return 0; buffer = talloc_strdup(request, fmt); if (!buffer) return 0; p = strchr(buffer, '.'); if (!p) return 0; *(p++) = '\0'; mi = module_find(modules, buffer); if (!mi) { RDEBUG("Failed finding module '%s'", buffer); fail: talloc_free(buffer); return 0; } q = strchr(p, '='); if (!q) { RDEBUG("Failed finding '=' in string '%s'", fmt); goto fail; } *(q++) = '\0'; if (strchr(p, '.') != NULL) { RDEBUG("Can't do sub-sections right now"); goto fail; } cp = cf_pair_find(mi->cs, p); if (!cp) { RDEBUG("No such item '%s'", p); goto fail; } /* * Copy the old value to the output buffer, that way * tests can restore it later, if they need to. */ len = strlcpy(*out, cf_pair_value(cp), outlen); if (cf_pair_replace(mi->cs, cp, q) < 0) { RDEBUG("Failed replacing pair"); goto fail; } base = mi->insthandle; variables = mi->entry->module->config; /* * Handle the known configuration parameters. */ for (i = 0; variables[i].name != NULL; i++) { int ret; if (variables[i].type == PW_TYPE_SUBSECTION) continue; /* else it's a CONF_PAIR */ /* * Not the pair we want. Skip it. */ if (strcmp(variables[i].name, p) != 0) continue; if (variables[i].data) { data = variables[i].data; /* prefer this. */ } else if (base) { data = ((char *)base) + variables[i].offset; } else { DEBUG2("Internal sanity check 2 failed in cf_section_parse"); goto fail; } /* * Parse the pair we found, or a default value. */ ret = cf_pair_parse(mi->cs, variables[i].name, variables[i].type, data, variables[i].dflt, variables[i].quote); if (ret < 0) { DEBUG2("Failed inserting new value into module instance data"); goto fail; } break; /* we found it, don't do any more */ } talloc_free(buffer); return len; }