static int generate_sql_clients(SQL_INST *inst) { SQLSOCK *sqlsocket; SQL_ROW row; char querystr[MAX_QUERY_LEN]; RADCLIENT *c; char *prefix_ptr = NULL; unsigned int i = 0; int numf = 0; DEBUG("rlm_sql (%s): Processing generate_sql_clients", inst->config->xlat_name); /* NAS query isn't xlat'ed */ strlcpy(querystr, inst->config->nas_query, sizeof(querystr)); DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s", inst->config->xlat_name, querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return -1; if (rlm_sql_select_query(sqlsocket,inst,querystr)){ radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s", inst->config->xlat_name,querystr, (inst->module->sql_error)(sqlsocket, inst->config)); sql_release_socket(inst,sqlsocket); return -1; } while(rlm_sql_fetch_row(sqlsocket, inst) == 0) { i++; row = sqlsocket->row; if (row == NULL) break; /* * The return data for each row MUST be in the following order: * * 0. Row ID (currently unused) * 1. Name (or IP address) * 2. Shortname * 3. Type * 4. Secret * 5. Virtual Server (optional) */ if (!row[0]){ radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i); continue; } if (!row[1]){ radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[2]){ radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[4]){ radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]); continue; } DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name, row[1],row[2],row[4]); c = rad_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); #ifdef WITH_DYNAMIC_CLIENTS c->dynamic = 1; #endif /* * Look for prefixes */ c->prefix = -1; prefix_ptr = strchr(row[1], '/'); if (prefix_ptr) { c->prefix = atoi(prefix_ptr + 1); if ((c->prefix < 0) || (c->prefix > 128)) { radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.", inst->config->xlat_name, prefix_ptr + 1); free(c); continue; } /* Replace '/' with '\0' */ *prefix_ptr = '\0'; } /* * Always get the numeric representation of IP */ if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) { radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s", inst->config->xlat_name, row[1], fr_strerror()); free(c); continue; } else { char buffer[256]; ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); c->longname = strdup(buffer); } if (c->prefix < 0) switch (c->ipaddr.af) { case AF_INET: c->prefix = 32; break; case AF_INET6: c->prefix = 128; break; default: break; } /* * Other values (secret, shortname, nastype, virtual_server) */ c->secret = strdup(row[4]); c->shortname = strdup(row[2]); if(row[3] != NULL) c->nastype = strdup(row[3]); numf = (inst->module->sql_num_fields)(sqlsocket, inst->config); if ((numf > 5) && (row[5] != NULL) && *row[5]) c->server = strdup(row[5]); DEBUG("rlm_sql (%s): Adding client %s (%s, server=%s) to clients list", inst->config->xlat_name, c->longname,c->shortname, c->server ? c->server : "<none>"); if (!client_add(NULL, c)) { sql_release_socket(inst, sqlsocket); DEBUG("rlm_sql (%s): Failed to add client %s (%s) to clients list. Maybe there's a duplicate?", inst->config->xlat_name, c->longname,c->shortname); client_free(c); return -1; } } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return 0; }
VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value) { char *p, *s=0; const char *cp, *cs; int x; size_t length; DICT_VALUE *dval; if (!value) return NULL; /* * Even for integers, dates and ip addresses we * keep the original string in vp->vp_strvalue. */ if (vp->type != PW_TYPE_TLV) { strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue)); vp->length = strlen(vp->vp_strvalue); } switch(vp->type) { case PW_TYPE_STRING: /* * Do escaping here */ p = vp->vp_strvalue; cp = value; length = 0; while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) { char c = *cp++; if (c == '\\') { switch (*cp) { case 'r': c = '\r'; cp++; break; case 'n': c = '\n'; cp++; break; case 't': c = '\t'; cp++; break; case '"': c = '"'; cp++; break; case '\'': c = '\''; cp++; break; case '\\': c = '\\'; cp++; break; case '`': c = '`'; cp++; break; case '\0': c = '\\'; /* no cp++ */ break; default: if ((cp[0] >= '0') && (cp[0] <= '9') && (cp[1] >= '0') && (cp[1] <= '9') && (cp[2] >= '0') && (cp[2] <= '9') && (sscanf(cp, "%3o", &x) == 1)) { c = x; cp += 3; } /* else just do '\\' */ } } *p++ = c; length++; } vp->vp_strvalue[length] = '\0'; vp->length = length; break; case PW_TYPE_IPADDR: /* * It's a comparison, not a real IP. */ if ((vp->operator == T_OP_REG_EQ) || (vp->operator == T_OP_REG_NE)) { break; } /* * FIXME: complain if hostname * cannot be resolved, or resolve later! */ s = NULL; if ((p = strrchr(value, '+')) != NULL && !p[1]) { cs = s = strdup(value); if (!s) return NULL; p = strrchr(s, '+'); if (p) *p = 0; vp->flags.addport = 1; } else { p = NULL; cs = value; } { fr_ipaddr_t ipaddr; if (ip_hton(cs, AF_INET, &ipaddr) < 0) { fr_strerror_printf("Failed to find IP address for %s", cs); free(s); return NULL; } vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr; } free(s); vp->length = 4; break; case PW_TYPE_BYTE: vp->length = 1; /* * Note that ALL integers are unsigned! */ vp->vp_integer = getint(value, &p); if (!*p) { if (vp->vp_integer > 255) { fr_strerror_printf("Byte value \"%s\" is larger than 255", value); return NULL; } break; } if (check_for_whitespace(p)) break; goto check_for_value; case PW_TYPE_SHORT: /* * Note that ALL integers are unsigned! */ vp->vp_integer = getint(value, &p); vp->length = 2; if (!*p) { if (vp->vp_integer > 65535) { fr_strerror_printf("Byte value \"%s\" is larger than 65535", value); return NULL; } break; } if (check_for_whitespace(p)) break; goto check_for_value; case PW_TYPE_INTEGER: /* * Note that ALL integers are unsigned! */ vp->vp_integer = getint(value, &p); vp->length = 4; if (!*p) break; if (check_for_whitespace(p)) break; check_for_value: /* * Look for the named value for the given * attribute. */ if ((dval = dict_valbyname(vp->attribute, value)) == NULL) { fr_strerror_printf("Unknown value %s for attribute %s", value, vp->name); return NULL; } vp->vp_integer = dval->value; break; case PW_TYPE_DATE: { /* * time_t may be 64 bits, whule vp_date * MUST be 32-bits. We need an * intermediary variable to handle * the conversions. */ time_t date; if (gettime(value, &date) < 0) { fr_strerror_printf("failed to parse time string " "\"%s\"", value); return NULL; } vp->vp_date = date; } vp->length = 4; break; case PW_TYPE_ABINARY: #ifdef ASCEND_BINARY if (strncasecmp(value, "0x", 2) == 0) { vp->type = PW_TYPE_OCTETS; goto do_octets; } if (ascend_parse_filter(vp) < 0 ) { char buffer[256]; snprintf(buffer, sizeof(buffer), "failed to parse Ascend binary attribute: %s", fr_strerror()); fr_strerror_printf("%s", buffer); return NULL; } break; /* * If Ascend binary is NOT defined, * then fall through to raw octets, so that * the user can at least make them by hand... */ do_octets: #endif /* raw octets: 0x01020304... */ case PW_TYPE_OCTETS: if (strncasecmp(value, "0x", 2) == 0) { uint8_t *us; cp = value + 2; us = vp->vp_octets; vp->length = 0; /* * There is only one character, * die. */ if ((strlen(cp) & 0x01) != 0) { fr_strerror_printf("Hex string is not an even length string."); return NULL; } while (*cp && (vp->length < MAX_STRING_LEN)) { unsigned int tmp; if (sscanf(cp, "%02x", &tmp) != 1) { fr_strerror_printf("Non-hex characters at %c%c", cp[0], cp[1]); return NULL; } cp += 2; *(us++) = tmp; vp->length++; } } break; case PW_TYPE_IFID: if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) { fr_strerror_printf("failed to parse interface-id " "string \"%s\"", value); return NULL; } vp->length = 8; break; case PW_TYPE_IPV6ADDR: { fr_ipaddr_t ipaddr; if (ip_hton(value, AF_INET6, &ipaddr) < 0) { char buffer[1024]; strlcpy(buffer, fr_strerror(), sizeof(buffer)); fr_strerror_printf("failed to parse IPv6 address " "string \"%s\": %s", value, buffer); return NULL; } vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr; vp->length = 16; /* length of IPv6 address */ } break; case PW_TYPE_IPV6PREFIX: p = strchr(value, '/'); if (!p || ((p - value) >= 256)) { fr_strerror_printf("invalid IPv6 prefix " "string \"%s\"", value); return NULL; } else { unsigned int prefix; char buffer[256], *eptr; memcpy(buffer, value, p - value); buffer[p - value] = '\0'; if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) { fr_strerror_printf("failed to parse IPv6 address " "string \"%s\"", value); return NULL; } prefix = strtoul(p + 1, &eptr, 10); if ((prefix > 128) || *eptr) { fr_strerror_printf("failed to parse IPv6 address " "string \"%s\"", value); return NULL; } vp->vp_octets[1] = prefix; } vp->vp_octets[0] = '\0'; vp->length = 16 + 2; break; case PW_TYPE_ETHERNET: { const char *c1, *c2; length = 0; cp = value; while (*cp) { if (cp[1] == ':') { c1 = hextab; c2 = memchr(hextab, tolower((int) cp[0]), 16); cp += 2; } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) { c1 = memchr(hextab, tolower((int) cp[0]), 16); c2 = memchr(hextab, tolower((int) cp[1]), 16); cp += 2; if (*cp == ':') cp++; } else { c1 = c2 = NULL; } if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) { fr_strerror_printf("failed to parse Ethernet address \"%s\"", value); return NULL; } vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab); length++; } } vp->length = 6; break; case PW_TYPE_COMBO_IP: if (inet_pton(AF_INET6, value, vp->vp_strvalue) > 0) { vp->type = PW_TYPE_IPV6ADDR; vp->length = 16; /* length of IPv6 address */ vp->vp_strvalue[vp->length] = '\0'; } else { fr_ipaddr_t ipaddr; if (ip_hton(value, AF_INET, &ipaddr) < 0) { fr_strerror_printf("Failed to find IPv4 address for %s", value); return NULL; } vp->type = PW_TYPE_IPADDR; vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr; vp->length = 4; } break; case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */ vp->vp_signed = (int32_t) strtol(value, &p, 10); vp->length = 4; break; case PW_TYPE_TLV: /* don't use this! */ if (strncasecmp(value, "0x", 2) != 0) { fr_strerror_printf("Invalid TLV specification"); return NULL; } length = strlen(value + 2) / 2; if (vp->length < length) { free(vp->vp_tlv); vp->vp_tlv = NULL; } vp->vp_tlv = malloc(length); if (!vp->vp_tlv) { fr_strerror_printf("No memory"); return NULL; } if (fr_hex2bin(value + 2, vp->vp_tlv, length) != length) { fr_strerror_printf("Invalid hex data in TLV"); return NULL; } vp->length = length; break; /* * Anything else. */ default: fr_strerror_printf("unknown attribute type %d", vp->type); return NULL; } return vp; }
/* * Allocate an IP number from the pool. */ static rlm_rcode_t 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; /* * 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; } DO(allocate_begin); DO(allocate_clear); 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(allocation, AF_INET, &ipaddr) < 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, &request->reply->vps, PW_FRAMED_IP_ADDRESS, 0); vp->vp_ipaddr = ip_allocation; DO(allocate_commit); inst->sql_inst->sql_release_socket(inst->sql_inst, handle); return do_logging(request, inst->log_success, RLM_MODULE_OK); }
int main(int argc, char **argv) { RADIUS_PACKET *req; char *p; int c; int port = 0; char *filename = NULL; FILE *fp; int count = 1; int id; id = ((int)getpid() & 0xff); fr_debug_flag = 0; radlog_dest = RADLOG_STDERR; while ((c = getopt(argc, argv, "c:d:f:hi:qst:r:S:xXv")) != EOF) { switch(c) { case 'c': if (!isdigit((int) *optarg)) usage(); count = atoi(optarg); break; case 'd': radius_dir = strdup(optarg); break; case 'f': filename = optarg; break; case 'q': do_output = 0; break; case 'x': debug_flag++; fr_debug_flag++; break; case 'X': #if 0 sha1_data_problems = 1; /* for debugging only */ #endif break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); break; case 'i': if (!isdigit((int) *optarg)) usage(); id = atoi(optarg); if ((id < 0) || (id > 255)) { usage(); } break; case 's': do_summary = 1; break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("radclient: $Id$ built on " __DATE__ " at " __TIME__ "\n"); exit(0); break; case 'S': fp = fopen(optarg, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", optarg, strerror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { fprintf(stderr, "radclient: Error reading %s: %s\n", optarg, strerror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { fprintf(stderr, "radclient: Secret in %s is too short\n", optarg); exit(1); } secret = filesecret; break; case 'h': default: usage(); break; } } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((secret == NULL) && (argc < 4))) { usage(); } if (!radius_dir) radius_dir = strdup(RADDBDIR); if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if ((req = rad_alloc(1)) == NULL) { fr_perror("radclient"); exit(1); } #if 0 { FILE *randinit; if((randinit = fopen("/dev/urandom", "r")) == NULL) { perror("/dev/urandom"); } else { fread(randctx.randrsl, 256, 1, randinit); fclose(randinit); } } fr_randinit(&randctx, 1); #endif req->id = id; /* * Strip port from hostname if needed. */ if ((p = strchr(argv[1], ':')) != NULL) { *p++ = 0; port = atoi(p); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "auth") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_AUTHENTICATION_REQUEST; } else if (strcmp(argv[2], "acct") == 0) { if (port == 0) port = getport("radacct"); if (port == 0) port = PW_ACCT_UDP_PORT; req->code = PW_ACCOUNTING_REQUEST; do_summary = 0; } else if (strcmp(argv[2], "status") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { if (port == 0) port = PW_POD_UDP_PORT; req->code = PW_DISCONNECT_REQUEST; } else if (isdigit((int) argv[2][0])) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = atoi(argv[2]); } else { usage(); } /* * Resolve hostname. */ req->dst_port = port; if (ip_hton(argv[1], AF_INET, &req->dst_ipaddr) < 0) { fprintf(stderr, "radclient: Failed to find IP address for host %s\n", argv[1]); exit(1); } /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * Read valuepairs. * Maybe read them, from stdin, if there's no * filename, or if the filename is '-'. */ if (filename && (strcmp(filename, "-") != 0)) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", filename, strerror(errno)); exit(1); } } else { fp = stdin; } /* * Send request. */ if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("radclient: socket: "); exit(1); } while(!filedone) { if(req->vps) pairfree(&req->vps); if ((req->vps = readvp2(fp, &filedone, "radeapclient:")) == NULL) { break; } sendrecv_eap(req); } free(radius_dir); if(do_summary) { printf("\n\t Total approved auths: %d\n", totalapp); printf("\t Total denied auths: %d\n", totaldeny); } return 0; }
int main(int argc, char **argv) { char *p; int c; char const *radius_dir = RADDBDIR; char filesecret[256]; FILE *fp; int do_summary = 0; int persec = 0; int parallel = 1; radclient_t *this; int force_af = AF_UNSPEC; fr_debug_flag = 0; talloc_set_log_stderr(); filename_tree = rbtree_create(filename_cmp, NULL, 0); if (!filename_tree) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } while ((c = getopt(argc, argv, "46c:d:f:Fhi:n:p:qr:sS:t:vx" #ifdef WITH_TCP "P:" #endif )) != EOF) switch(c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'c': if (!isdigit((int) *optarg)) usage(); resend_count = atoi(optarg); break; case 'd': radius_dir = optarg; break; case 'f': rbtree_insert(filename_tree, optarg); break; case 'F': print_filename = 1; break; case 'i': /* currently broken */ if (!isdigit((int) *optarg)) usage(); last_used_id = atoi(optarg); if ((last_used_id < 0) || (last_used_id > 255)) { usage(); } break; case 'n': persec = atoi(optarg); if (persec <= 0) usage(); break; /* * Note that sending MANY requests in * parallel can over-run the kernel * queues, and Linux will happily discard * packets. So even if the server responds, * the client may not see the response. */ case 'p': parallel = atoi(optarg); if (parallel <= 0) usage(); break; #ifdef WITH_TCP case 'P': proto = optarg; if (strcmp(proto, "tcp") != 0) { if (strcmp(proto, "udp") == 0) { proto = NULL; } else { usage(); } } else { ipproto = IPPROTO_TCP; } break; #endif case 'q': do_output = 0; fr_log_fp = NULL; /* no output from you, either! */ break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 's': do_summary = 1; break; case 'S': fp = fopen(optarg, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", optarg, strerror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { fprintf(stderr, "radclient: Error reading %s: %s\n", optarg, strerror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { fprintf(stderr, "radclient: Secret in %s is too short\n", optarg); exit(1); } secret = filesecret; break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", radclient_version); exit(0); break; case 'x': fr_debug_flag++; fr_log_fp = stdout; break; case 'h': default: usage(); break; } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((secret == NULL) && (argc < 4))) { usage(); } if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } /* * Resolve hostname. */ if (force_af == AF_UNSPEC) force_af = AF_INET; server_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(hostname, force_af, &server_ipaddr) < 0) { fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "auth") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_CODE_AUTHENTICATION_REQUEST; } else if (strcmp(argv[2], "challenge") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_CODE_ACCESS_CHALLENGE; } else if (strcmp(argv[2], "acct") == 0) { if (server_port == 0) server_port = getport("radacct"); if (server_port == 0) server_port = PW_ACCT_UDP_PORT; packet_code = PW_CODE_ACCOUNTING_REQUEST; do_summary = 0; } else if (strcmp(argv[2], "status") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_CODE_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_CODE_DISCONNECT_REQUEST; } else if (strcmp(argv[2], "coa") == 0) { if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_CODE_COA_REQUEST; } else if (strcmp(argv[2], "auto") == 0) { packet_code = -1; } else if (isdigit((int) argv[2][0])) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = atoi(argv[2]); } else { usage(); } /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * If no '-f' is specified, we're reading from stdin. */ if (rbtree_num_elements(filename_tree) == 0) { if (!radclient_init("-")) exit(1); } /* * Walk over the list of filenames, creating the requests. */ if (rbtree_walk(filename_tree, InOrder, filename_walk, NULL) != 0) { fprintf(stderr, "Failed walking over filenames\n"); exit(1); } /* * No packets read. Die. */ if (!radclient_head) { fprintf(stderr, "radclient: Nothing to send.\n"); exit(1); } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = radclient_head->request->src_ipaddr; client_port = radclient_head->request->src_port; } #ifdef WITH_TCP if (proto) { sockfd = fr_tcp_client_socket(NULL, &server_ipaddr, server_port); } else #endif sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { fprintf(stderr, "radclient: socket: %s\n", fr_strerror()); exit(1); } pl = fr_packet_list_create(1); if (!pl) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, server_port, NULL)) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } /* * Walk over the list of packets, sanity checking * everything. */ for (this = radclient_head; this != NULL; this = this->next) { this->request->src_ipaddr = client_ipaddr; this->request->src_port = client_port; if (radclient_sane(this) != 0) { exit(1); } } /* * Walk over the packets to send, until * we're all done. * * FIXME: This currently busy-loops until it receives * all of the packets. It should really have some sort of * send packet, get time to wait, select for time, etc. * loop. */ do { int n = parallel; radclient_t *next; char const *filename = NULL; done = 1; sleep_time = -1; /* * Walk over the packets, sending them. */ for (this = radclient_head; this != NULL; this = next) { next = this->next; /* * If there's a packet to receive, * receive it, but don't wait for a * packet. */ recv_one_packet(0); /* * This packet is done. Delete it. */ if (this->done) { radclient_free(this); continue; } /* * Packets from multiple '-f' are sent * in parallel. * * Packets from one file are sent in * series, unless '-p' is specified, in * which case N packets from each file * are sent in parallel. */ if (this->filename != filename) { filename = this->filename; n = parallel; } if (n > 0) { n--; /* * Send the current packet. */ send_one_packet(this); /* * Wait a little before sending * the next packet, if told to. */ if (persec) { struct timeval tv; /* * Don't sleep elsewhere. */ sleep_time = 0; if (persec == 1) { tv.tv_sec = 1; tv.tv_usec = 0; } else { tv.tv_sec = 0; tv.tv_usec = 1000000/persec; } /* * Sleep for milliseconds, * portably. * * If we get an error or * a signal, treat it like * a normal timeout. */ select(0, NULL, NULL, NULL, &tv); } /* * If we haven't sent this packet * often enough, we're not done, * and we shouldn't sleep. */ if (this->resend < resend_count) { done = 0; sleep_time = 0; } } else { /* haven't sent this packet, we're not done */ assert(this->done == 0); assert(this->reply == NULL); done = 0; } } /* * Still have outstanding requests. */ if (fr_packet_list_num_elements(pl) > 0) { done = 0; } else { sleep_time = 0; } /* * Nothing to do until we receive a request, so * sleep until then. Once we receive one packet, * we go back, and walk through the whole list again, * sending more packets (if necessary), and updating * the sleep time. */ if (!done && (sleep_time > 0)) { recv_one_packet(sleep_time); } } while (!done); rbtree_free(filename_tree); fr_packet_list_free(pl); while (radclient_head) radclient_free(radclient_head); dict_free(); if (do_summary) { printf("\n\t Total approved auths: %d\n", totalapp); printf("\t Total denied auths: %d\n", totaldeny); printf("\t Total lost auths: %d\n", totallost); } if (success) return 0; return 1; }
int main(int argc, char **argv) { RADIUS_PACKET *req; char *p; int c; uint16_t port = 0; char *filename = NULL; FILE *fp; int id; int force_af = AF_UNSPEC; static fr_log_t radclient_log = { .colourise = true, .fd = STDOUT_FILENO, .dst = L_DST_STDOUT, .file = NULL, .debug_file = NULL, }; radlog_init(&radclient_log, false); /* * We probably don't want to free the talloc autofree context * directly, so we'll allocate a new context beneath it, and * free that before any leak reports. */ TALLOC_CTX *autofree = talloc_init("main"); id = ((int)getpid() & 0xff); fr_debug_flag = 0; set_radius_dir(autofree, RADIUS_DIR); while ((c = getopt(argc, argv, "46c:d:D:f:hi:qst:r:S:xXv")) != EOF) { switch (c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'd': set_radius_dir(autofree, optarg); break; case 'D': main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg); break; case 'f': filename = optarg; break; case 'q': do_output = 0; break; case 'x': debug_flag++; fr_debug_flag++; break; case 'X': #if 0 sha1_data_problems = 1; /* for debugging only */ #endif break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); break; case 'i': if (!isdigit((int) *optarg)) usage(); id = atoi(optarg); if ((id < 0) || (id > 255)) { usage(); } break; case 's': do_summary = 1; break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("$Id: d10077738d3693b21dbec74b1e28fa811ecd752d $ built on "__DATE__ "at "__TIME__ ""); exit(0); case 'S': fp = fopen(optarg, "r"); if (!fp) { ERROR("Error opening %s: %s", optarg, fr_syserror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { ERROR("Error reading %s: %s", optarg, fr_syserror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { ERROR("Secret in %s is too short", optarg); exit(1); } secret = filesecret; break; case 'h': default: usage(); } } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((!secret) && (argc < 4))) { usage(); } if (!main_config.dictionary_dir) { main_config.dictionary_dir = DICTDIR; } /* * Read the distribution dictionaries first, then * the ones in raddb. */ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY); if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) { ERROR("Errors reading dictionary: %s", fr_strerror()); exit(1); } /* * It's OK if this one doesn't exist. */ int rcode = dict_read(radius_dir, RADIUS_DICTIONARY); if (rcode == -1) { ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY, fr_strerror()); exit(1); } /* * We print this after reading it. That way if * it doesn't exist, it's OK, and we don't print * anything. */ if (rcode == 0) { DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY); } req = rad_alloc(NULL, true); if (!req) { ERROR("%s", fr_strerror()); exit(1); } req->id = id; /* * Resolve hostname. */ if (force_af == AF_UNSPEC) force_af = AF_INET; req->dst_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(&req->dst_ipaddr, force_af, hostname, false) < 0) { ERROR("Failed to find IP address for host %s: %s", hostname, fr_syserror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "auth") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_CODE_ACCESS_REQUEST; } else if (strcmp(argv[2], "acct") == 0) { if (port == 0) port = getport("radacct"); if (port == 0) port = PW_ACCT_UDP_PORT; req->code = PW_CODE_ACCOUNTING_REQUEST; do_summary = 0; } else if (strcmp(argv[2], "status") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_CODE_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { if (port == 0) port = PW_POD_UDP_PORT; req->code = PW_CODE_DISCONNECT_REQUEST; } else if (isdigit((int) argv[2][0])) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = atoi(argv[2]); } else { usage(); } req->dst_port = port; /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * Read valuepairs. * Maybe read them, from stdin, if there's no * filename, or if the filename is '-'. */ if (filename && (strcmp(filename, "-") != 0)) { fp = fopen(filename, "r"); if (!fp) { ERROR("Error opening %s: %s", filename, fr_syserror(errno)); exit(1); } } else { fp = stdin; } /* * Send request. */ if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ERROR("socket: %s", fr_syserror(errno)); exit(1); } while (!filedone) { if (req->vps) pairfree(&req->vps); if (readvp2(NULL, &req->vps, fp, &filedone) < 0) { ERROR("%s", fr_strerror()); break; } sendrecv_eap(req); } if (do_summary) { INFO("\n\t Total approved auths: %d", totalapp); INFO("\t Total denied auths: %d", totaldeny); } talloc_free(autofree); return 0; } /* * given a radius request with some attributes in the EAP range, build * them all into a single EAP-Message body. * * Note that this function will build multiple EAP-Message bodies * if there are multiple eligible EAP-types. This is incorrect, as the * recipient will in fact concatenate them. * * XXX - we could break the loop once we process one type. Maybe this * just deserves an assert? * */ static void map_eap_methods(RADIUS_PACKET *req) { VALUE_PAIR *vp, *vpnext; int id, eapcode; int eap_method; eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t); vp = pairfind(req->vps, PW_EAP_ID, 0, TAG_ANY); if(!vp) { id = ((int)getpid() & 0xff); } else { id = vp->vp_integer; } vp = pairfind(req->vps, PW_EAP_CODE, 0, TAG_ANY); if(!vp) { eapcode = PW_EAP_REQUEST; } else { eapcode = vp->vp_integer; } for(vp = req->vps; vp != NULL; vp = vpnext) { /* save it in case it changes! */ vpnext = vp->next; if(vp->da->attr >= PW_EAP_TYPE_BASE && vp->da->attr < PW_EAP_TYPE_BASE+256) { break; } } if(!vp) { return; } eap_method = vp->da->attr - PW_EAP_TYPE_BASE; switch (eap_method) { case PW_EAP_IDENTITY: case PW_EAP_NOTIFICATION: case PW_EAP_NAK: case PW_EAP_MD5: case PW_EAP_OTP: case PW_EAP_GTC: case PW_EAP_TLS: case PW_EAP_LEAP: case PW_EAP_TTLS: case PW_EAP_PEAP: default: /* * no known special handling, it is just encoded as an * EAP-message with the given type. */ /* nuke any existing EAP-Messages */ pairdelete(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY); pt_ep->code = eapcode; pt_ep->id = id; pt_ep->type.num = eap_method; pt_ep->type.length = vp->vp_length; pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length); talloc_set_type(pt_ep->type.data, uint8_t); eap_basic_compose(req, pt_ep); } }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int status; int argval; bool spawn_flag = true; bool write_pid = false; bool display_version = false; int flag = 0; int from_child[2] = {-1, -1}; /* * We probably don't want to free the talloc autofree context * directly, so we'll allocate a new context beneath it, and * free that before any leak reports. */ TALLOC_CTX *autofree = talloc_init("main"); #ifdef OSFC2 set_auth_parameters(argc, argv); #endif if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; #ifdef WIN32 { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { fprintf(stderr, "%s: Unable to initialize socket library.\n", progname); exit(EXIT_FAILURE); } } #endif debug_flag = 0; set_radius_dir(autofree, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&main_config, 0, sizeof(main_config)); main_config.myip.af = AF_UNSPEC; main_config.port = 0; main_config.name = "radiusd"; main_config.daemonize = true; /* * Don't put output anywhere until we get told a little * more. */ default_log.dst = L_DST_NULL; default_log.fd = -1; main_config.log_file = NULL; /* Process the options. */ while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) { switch (argval) { case 'C': check_config = true; spawn_flag = false; main_config.daemonize = false; break; case 'd': set_radius_dir(autofree, optarg); break; case 'D': main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg); break; case 'f': main_config.daemonize = false; break; case 'h': usage(0); break; case 'l': if (strcmp(optarg, "stdout") == 0) { goto do_stdout; } main_config.log_file = strdup(optarg); default_log.dst = L_DST_FILES; default_log.fd = open(main_config.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (default_log.fd < 0) { fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno)); exit(EXIT_FAILURE); } fr_log_fp = fdopen(default_log.fd, "a"); break; case 'i': if (ip_hton(&main_config.myip, AF_UNSPEC, optarg, false) < 0) { fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg); exit(EXIT_FAILURE); } flag |= 1; break; case 'n': main_config.name = optarg; break; case 'm': main_config.debug_memory = true; break; case 'M': main_config.memory_report = true; main_config.debug_memory = true; break; case 'p': { unsigned long port; port = strtoul(optarg, 0, 10); if ((port == 0) || (port > UINT16_MAX)) { fprintf(stderr, "radiusd: Invalid port number \"%s\"\n", optarg); exit(EXIT_FAILURE); } main_config.port = (uint16_t) port; flag |= 2; } break; case 'P': /* Force the PID to be written, even in -f mode */ write_pid = true; break; case 's': /* Single process mode */ spawn_flag = false; main_config.daemonize = false; break; case 't': /* no child threads */ spawn_flag = false; break; case 'v': display_version = true; break; case 'X': spawn_flag = false; main_config.daemonize = false; debug_flag += 2; main_config.log_auth = true; main_config.log_auth_badpass = true; main_config.log_auth_goodpass = true; do_stdout: fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; break; case 'x': debug_flag++; break; default: usage(1); break; } } /* * Mismatch between the binary and the libraries it depends on. */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radiusd"); exit(EXIT_FAILURE); } if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) exit(EXIT_FAILURE); /* * Mismatch between build time OpenSSL and linked SSL, better to die * here than segfault later. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (ssl_check_consistency() < 0) exit(EXIT_FAILURE); #endif if (flag && (flag != 0x03)) { fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n"); exit(EXIT_FAILURE); } /* * According to the talloc peeps, no two threads may modify any part of * a ctx tree with a common root without synchronisation. * * So we can't run with a null context and threads. */ if (main_config.memory_report) { if (spawn_flag) { fprintf(stderr, "radiusd: The server cannot produce memory reports (-M) in threaded mode\n"); exit(EXIT_FAILURE); } talloc_enable_null_tracking(); } else { talloc_disable_null_tracking(); } /* * Better here, so it doesn't matter whether we get passed -xv or -vx. */ if (display_version) { /* Don't print timestamps */ debug_flag += 2; fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; version(); exit(EXIT_SUCCESS); } if (debug_flag) version(); /* * Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid, * so we need to check whether we can attach before calling those functions * (in main_config_init()). */ fr_store_debug_state(); /* * Initialising OpenSSL once, here, is safer than having individual modules do it. */ #ifdef HAVE_OPENSSL_CRYPTO_H tls_global_init(); #endif /* * Read the configuration files, BEFORE doing anything else. */ if (main_config_init() < 0) exit(EXIT_FAILURE); /* * This is very useful in figuring out why the panic_action didn't fire. */ INFO("%s", fr_debug_state_to_msg(fr_debug_state)); /* * Check for vulnerabilities in the version of libssl were linked against. */ #if defined(HAVE_OPENSSL_CRYPTO_H) && defined(ENABLE_OPENSSL_VERSION_CHECK) if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) exit(EXIT_FAILURE); #endif /* * Set the panic action (if required) */ if (main_config.panic_action && #ifndef NDEBUG !getenv("PANIC_ACTION") && #endif (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) { fr_perror("radiusd"); exit(EXIT_FAILURE); } #ifndef __MINGW32__ /* * Disconnect from session */ if (main_config.daemonize) { pid_t pid; int devnull; /* * Really weird things happen if we leave stdin open and call things like * system() later. */ devnull = open("/dev/null", O_RDWR); if (devnull < 0) { ERROR("Failed opening /dev/null: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } dup2(devnull, STDIN_FILENO); close(devnull); if (pipe(from_child) != 0) { ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } pid = fork(); if (pid < 0) { ERROR("Couldn't fork: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } /* * The parent exits, so the child can run in the background. * * As the child can still encounter an error during initialisation * we do a blocking read on a pipe between it and the parent. * * Just before entering the event loop the child will send a success * or failure message to the parent, via the pipe. */ if (pid > 0) { uint8_t ret = 0; int stat_loc; /* So the pipe is correctly widowed if the child exits */ close(from_child[1]); /* * The child writes a 0x01 byte on success, and closes * the pipe on error. */ if ((read(from_child[0], &ret, 1) < 0)) { ret = 0; } /* For cleanliness... */ close(from_child[0]); /* Don't turn children into zombies */ if (!ret) { waitpid(pid, &stat_loc, WNOHANG); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* so the pipe is correctly widowed if the parent exits?! */ close(from_child[0]); # ifdef HAVE_SETSID setsid(); # endif } #endif /* * Ensure that we're using the CORRECT pid after forking, NOT the one * we started with. */ radius_pid = getpid(); /* * Initialize any event loops just enough so module instantiations can * add fd/event to them, but do not start them yet. * * This has to be done post-fork in case we're using kqueue, where the * queue isn't inherited by the child process. */ if (!radius_event_init(autofree)) exit(EXIT_FAILURE); /* * Load the modules */ if (modules_init(main_config.config) < 0) exit(EXIT_FAILURE); /* * Redirect stderr/stdout as appropriate. */ if (radlog_init(&default_log, main_config.daemonize) < 0) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } /* * Start the event loop(s) and threads. */ radius_event_start(main_config.config, spawn_flag); /* * Now that we've set everything up, we can install the signal * handlers. Before this, if we get any signal, we don't know * what to do, so we might as well do the default, and die. */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif if ((fr_set_signal(SIGHUP, sig_hup) < 0) || (fr_set_signal(SIGTERM, sig_fatal) < 0)) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } /* * If we're debugging, then a CTRL-C will cause the server to die * immediately. Use SIGTERM to shut down the server cleanly in * that case. */ if (main_config.debug_memory || (debug_flag == 0)) { if ((fr_set_signal(SIGINT, sig_fatal) < 0) #ifdef SIGQUIT || (fr_set_signal(SIGQUIT, sig_fatal) < 0) #endif ) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } } /* * Everything seems to have loaded OK, exit gracefully. */ if (check_config) { DEBUG("Configuration appears to be OK"); /* for -C -m|-M */ if (main_config.debug_memory) goto cleanup; exit(EXIT_SUCCESS); } #ifdef WITH_STATS radius_stats_init(0); #endif /* * Write the PID always if we're running as a daemon. */ if (main_config.daemonize) write_pid = true; /* * Write the PID after we've forked, so that we write the correct one. */ if (write_pid) { FILE *fp; fp = fopen(main_config.pid_file, "w"); if (fp != NULL) { /* * @fixme What about following symlinks, * and having it over-write a normal file? */ fprintf(fp, "%d\n", (int) radius_pid); fclose(fp); } else { ERROR("Failed creating PID file %s: %s", main_config.pid_file, fr_syserror(errno)); exit(EXIT_FAILURE); } } exec_trigger(NULL, NULL, "server.start", false); /* * Inform the parent (who should still be waiting) that the rest of * initialisation went OK, and that it should exit with a 0 status. * If we don't get this far, then we just close the pipe on exit, and the * parent gets a read failure. */ if (main_config.daemonize) { if (write(from_child[1], "\001", 1) < 0) { WARN("Failed informing parent of successful start: %s", fr_syserror(errno)); } close(from_child[1]); } /* * Clear the libfreeradius error buffer. */ fr_strerror(); /* * Initialise the state rbtree (used to link multiple rounds of challenges). */ fr_state_init(); /* * Process requests until HUP or exit. */ while ((status = radius_event_process()) == 0x80) { #ifdef WITH_STATS radius_stats_init(1); #endif main_config_hup(); } if (status < 0) { ERROR("Exiting due to internal error: %s", fr_strerror()); rcode = EXIT_FAILURE; } else { INFO("Exiting normally"); } /* * Ignore the TERM signal: we're about to die. */ signal(SIGTERM, SIG_IGN); /* * Fire signal and stop triggers after ignoring SIGTERM, so handlers are * not killed with the rest of the process group, below. */ if (status == 2) exec_trigger(NULL, NULL, "server.signal.term", true); exec_trigger(NULL, NULL, "server.stop", false); /* * Send a TERM signal to all associated processes * (including us, which gets ignored.) */ #ifndef __MINGW32__ if (spawn_flag) kill(-radius_pid, SIGTERM); #endif /* * We're exiting, so we can delete the PID file. * (If it doesn't exist, we can ignore the error returned by unlink) */ if (main_config.daemonize) unlink(main_config.pid_file); radius_event_free(); cleanup: /* * Detach any modules. */ modules_free(); xlat_free(); /* modules may have xlat's */ fr_state_delete(); /* * Free the configuration items. */ main_config_free(); #ifdef WIN32 WSACleanup(); #endif #ifdef HAVE_OPENSSL_CRYPTO_H tls_global_cleanup(); #endif /* * So we don't see autofreed memory in the talloc report */ talloc_free(autofree); if (main_config.memory_report) { INFO("Allocated memory at time of report:"); fr_log_talloc_report(NULL); } return rcode; }
int main(int argc, char **argv) { int c; char const *radius_dir = RADDBDIR; char const *dict_dir = DICTDIR; char filesecret[256]; FILE *fp; int do_summary = false; int persec = 0; int parallel = 1; rc_request_t *this; int force_af = AF_UNSPEC; /* * It's easier having two sets of flags to set the * verbosity of library calls and the verbosity of * radclient. */ fr_debug_flag = 0; fr_log_fp = stdout; #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("radclient"); exit(EXIT_FAILURE); } #endif talloc_set_log_stderr(); filename_tree = rbtree_create(NULL, filename_cmp, NULL, 0); if (!filename_tree) { oom: ERROR("Out of memory"); exit(1); } while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:n:p:qr:sS:t:vx" #ifdef WITH_TCP "P:" #endif )) != EOF) switch (c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'c': if (!isdigit((int) *optarg)) usage(); resend_count = atoi(optarg); break; case 'D': dict_dir = optarg; break; case 'd': radius_dir = optarg; break; case 'f': { char const *p; rc_file_pair_t *files; files = talloc(talloc_autofree_context(), rc_file_pair_t); if (!files) goto oom; p = strchr(optarg, ':'); if (p) { files->packets = talloc_strndup(files, optarg, p - optarg); if (!files->packets) goto oom; files->filters = p + 1; } else { files->packets = optarg; files->filters = NULL; } rbtree_insert(filename_tree, (void *) files); } break; case 'F': print_filename = true; break; case 'i': /* currently broken */ if (!isdigit((int) *optarg)) usage(); last_used_id = atoi(optarg); if ((last_used_id < 0) || (last_used_id > 255)) { usage(); } break; case 'n': persec = atoi(optarg); if (persec <= 0) usage(); break; /* * Note that sending MANY requests in * parallel can over-run the kernel * queues, and Linux will happily discard * packets. So even if the server responds, * the client may not see the reply. */ case 'p': parallel = atoi(optarg); if (parallel <= 0) usage(); break; #ifdef WITH_TCP case 'P': proto = optarg; if (strcmp(proto, "tcp") != 0) { if (strcmp(proto, "udp") == 0) { proto = NULL; } else { usage(); } } else { ipproto = IPPROTO_TCP; } break; #endif case 'q': do_output = false; fr_log_fp = NULL; /* no output from you, either! */ break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 's': do_summary = true; break; case 'S': { char *p; fp = fopen(optarg, "r"); if (!fp) { ERROR("Error opening %s: %s", optarg, fr_syserror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { ERROR("Error reading %s: %s", optarg, fr_syserror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { ERROR("Secret in %s is too short", optarg); exit(1); } secret = filesecret; } break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': DEBUG("%s", radclient_version); exit(0); case 'x': fr_debug_flag++; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((secret == NULL) && (argc < 4))) { ERROR("Insufficient arguments"); usage(); } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radclient"); return 1; } if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radclient"); return 1; } fr_strerror(); /* Clear the error buffer */ /* * Get the request type */ if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { ERROR("Unrecognised request type \"%s\"", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } /* * Resolve hostname. */ if (force_af == AF_UNSPEC) force_af = AF_INET; server_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { char *p; char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) { ERROR("Failed to find IP address for host %s: %s", hostname, strerror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); /* * Work backwards from the port to determine the packet type */ if (packet_code == PW_CODE_UNDEFINED) packet_code = radclient_get_code(server_port); } radclient_get_port(packet_code, &server_port); /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * If no '-f' is specified, we're reading from stdin. */ if (rbtree_num_elements(filename_tree) == 0) { rc_file_pair_t *files; files = talloc_zero(talloc_autofree_context(), rc_file_pair_t); files->packets = "-"; if (!radclient_init(files, files)) { exit(1); } } /* * Walk over the list of filenames, creating the requests. */ if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) { ERROR("Failed parsing input files"); exit(1); } /* * No packets read. Die. */ if (!request_head) { ERROR("Nothing to send"); exit(1); } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request_head->packet->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; } else { client_ipaddr = request_head->packet->src_ipaddr; } client_port = request_head->packet->src_port; #ifdef WITH_TCP if (proto) { sockfd = fr_socket_client_tcp(NULL, &server_ipaddr, server_port, false); } else #endif sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { ERROR("Error opening socket"); exit(1); } pl = fr_packet_list_create(1); if (!pl) { ERROR("Out of memory"); exit(1); } if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, server_port, NULL)) { ERROR("Out of memory"); exit(1); } /* * Walk over the list of packets, sanity checking * everything. */ for (this = request_head; this != NULL; this = this->next) { this->packet->src_ipaddr = client_ipaddr; this->packet->src_port = client_port; if (radclient_sane(this) != 0) { exit(1); } } /* * Walk over the packets to send, until * we're all done. * * FIXME: This currently busy-loops until it receives * all of the packets. It should really have some sort of * send packet, get time to wait, select for time, etc. * loop. */ do { int n = parallel; rc_request_t *next; char const *filename = NULL; done = true; sleep_time = -1; /* * Walk over the packets, sending them. */ for (this = request_head; this != NULL; this = next) { next = this->next; /* * If there's a packet to receive, * receive it, but don't wait for a * packet. */ recv_one_packet(0); /* * This packet is done. Delete it. */ if (this->done) { talloc_free(this); continue; } /* * Packets from multiple '-f' are sent * in parallel. * * Packets from one file are sent in * series, unless '-p' is specified, in * which case N packets from each file * are sent in parallel. */ if (this->files->packets != filename) { filename = this->files->packets; n = parallel; } if (n > 0) { n--; /* * Send the current packet. */ send_one_packet(this); /* * Wait a little before sending * the next packet, if told to. */ if (persec) { struct timeval tv; /* * Don't sleep elsewhere. */ sleep_time = 0; if (persec == 1) { tv.tv_sec = 1; tv.tv_usec = 0; } else { tv.tv_sec = 0; tv.tv_usec = 1000000/persec; } /* * Sleep for milliseconds, * portably. * * If we get an error or * a signal, treat it like * a normal timeout. */ select(0, NULL, NULL, NULL, &tv); } /* * If we haven't sent this packet * often enough, we're not done, * and we shouldn't sleep. */ if (this->resend < resend_count) { done = false; sleep_time = 0; } } else { /* haven't sent this packet, we're not done */ assert(this->done == false); assert(this->reply == NULL); done = false; } } /* * Still have outstanding requests. */ if (fr_packet_list_num_elements(pl) > 0) { done = false; } else { sleep_time = 0; } /* * Nothing to do until we receive a request, so * sleep until then. Once we receive one packet, * we go back, and walk through the whole list again, * sending more packets (if necessary), and updating * the sleep time. */ if (!done && (sleep_time > 0)) { recv_one_packet(sleep_time); } } while (!done); rbtree_free(filename_tree); fr_packet_list_free(pl); while (request_head) TALLOC_FREE(request_head); dict_free(); if (do_summary) { DEBUG("Packet summary:\n" "\tAccepted : %" PRIu64 "\n" "\tRejected : %" PRIu64 "\n" "\tLost : %" PRIu64 "\n" "\tPassed filter : %" PRIu64 "\n" "\tFailed filter : %" PRIu64, stats.accepted, stats.rejected, stats.lost, stats.passed, stats.failed ); } if ((stats.lost > 0) || (stats.failed > 0)) { exit(1); } exit(0); }
/* * Allocate an IP number from the pool. */ static int sqlippool_postauth(void *instance, REQUEST * request) { rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance; char allocation[MAX_STRING_LEN]; int allocation_len; uint32_t ip_allocation; VALUE_PAIR * vp; SQLSOCK * sqlsocket; fr_ipaddr_t ipaddr; char logstr[MAX_STRING_LEN]; char sqlusername[MAX_STRING_LEN]; /* * If there is a Framed-IP-Address attribute in the reply do nothing */ if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) { /* We already have a Framed-IP-Address */ radius_xlat(logstr, sizeof(logstr), data->log_exists, request, NULL); RDEBUG("Framed-IP-Address already exists"); return do_logging(logstr, RLM_MODULE_NOOP); } if (pairfind(request->config_items, PW_POOL_NAME) == NULL) { RDEBUG("No Pool-Name defined."); radius_xlat(logstr, sizeof(logstr), data->log_nopool, request, NULL); return do_logging(logstr, RLM_MODULE_NOOP); } sqlsocket = data->sql_inst->sql_get_socket(data->sql_inst); if (sqlsocket == NULL) { RDEBUG("cannot allocate sql connection"); return RLM_MODULE_FAIL; } if (data->sql_inst->sql_set_user(data->sql_inst, request, sqlusername, NULL) < 0) { return RLM_MODULE_FAIL; } /* * BEGIN */ sqlippool_command(data->allocate_begin, sqlsocket, data, request, (char *) NULL, 0); /* * CLEAR */ sqlippool_command(data->allocate_clear, sqlsocket, data, request, (char *) NULL, 0); /* * FIND */ allocation_len = sqlippool_query1(allocation, sizeof(allocation), data->allocate_find, sqlsocket, data, request, (char *) NULL, 0); /* * Nothing found... */ if (allocation_len == 0) { /* * COMMIT */ sqlippool_command(data->allocate_commit, sqlsocket, instance, request, (char *) NULL, 0); /* * Should we perform pool-check ? */ if (data->pool_check && *data->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), data->pool_check, sqlsocket, data, request, (char *) NULL, 0); data->sql_inst->sql_release_socket(data->sql_inst, sqlsocket); 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"); radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL); return do_logging(logstr, 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; } data->sql_inst->sql_release_socket(data->sql_inst, sqlsocket); RDEBUG("IP address could not be allocated."); radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL); return do_logging(logstr, RLM_MODULE_NOOP); } /* * FIXME: Make it work with the ipv6 addresses */ if ((ip_hton(allocation, AF_INET, &ipaddr) < 0) || ((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE)) { /* * COMMIT */ sqlippool_command(data->allocate_commit, sqlsocket, instance, request, (char *) NULL, 0); RDEBUG("Invalid IP number [%s] returned from database query.", allocation); data->sql_inst->sql_release_socket(data->sql_inst, sqlsocket); radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL); return do_logging(logstr, RLM_MODULE_NOOP); } /* * UPDATE */ sqlippool_command(data->allocate_update, sqlsocket, data, request, allocation, allocation_len); RDEBUG("Allocated IP %s [%08x]", allocation, ip_allocation); vp = radius_paircreate(request, &request->reply->vps, PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR); vp->vp_ipaddr = ip_allocation; /* * COMMIT */ sqlippool_command(data->allocate_commit, sqlsocket, data, request, (char *) NULL, 0); data->sql_inst->sql_release_socket(data->sql_inst, sqlsocket); radius_xlat(logstr, sizeof(logstr), data->log_success, request, NULL); return do_logging(logstr, RLM_MODULE_OK); }
int main(int argc, char **argv) { RADIUS_PACKET *req; char *p; int c; uint16_t port = 0; char *filename = NULL; FILE *fp; int id; int force_af = AF_UNSPEC; /* * We probably don't want to free the talloc autofree context * directly, so we'll allocate a new context beneath it, and * free that before any leak reports. */ TALLOC_CTX *autofree = talloc_init("main"); id = ((int)getpid() & 0xff); fr_debug_flag = 0; radlog_dest = L_DST_STDERR; set_radius_dir(autofree, RADIUS_DIR); while ((c = getopt(argc, argv, "46c:d:D:f:hi:qst:r:S:xXv")) != EOF) { switch(c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'd': set_radius_dir(autofree, optarg); break; case 'D': main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg); break; case 'f': filename = optarg; break; case 'q': do_output = 0; break; case 'x': debug_flag++; fr_debug_flag++; break; case 'X': #if 0 sha1_data_problems = 1; /* for debugging only */ #endif break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); break; case 'i': if (!isdigit((int) *optarg)) usage(); id = atoi(optarg); if ((id < 0) || (id > 255)) { usage(); } break; case 's': do_summary = 1; break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("radeapclient: $Id: 2716390e5a1293ae1a4b712c52e220a603721d2b $ built on " __DATE__ " at " __TIME__ "\n"); exit(0); break; case 'S': fp = fopen(optarg, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", optarg, fr_syserror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { fprintf(stderr, "radclient: Error reading %s: %s\n", optarg, fr_syserror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { fprintf(stderr, "radclient: Secret in %s is too short\n", optarg); exit(1); } secret = filesecret; break; case 'h': default: usage(); break; } } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((!secret) && (argc < 4))) { usage(); } if (!main_config.dictionary_dir) { main_config.dictionary_dir = DICTDIR; } /* * Read the distribution dictionaries first, then * the ones in raddb. */ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY); if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) { ERROR("Errors reading dictionary: %s", fr_strerror()); exit(1); } /* * It's OK if this one doesn't exist. */ int rcode = dict_read(radius_dir, RADIUS_DICTIONARY); if (rcode == -1) { ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY, fr_strerror()); exit(1); } /* * We print this after reading it. That way if * it doesn't exist, it's OK, and we don't print * anything. */ if (rcode == 0) { DEBUG2("including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY); } req = rad_alloc(NULL, 1); if (!req) { fr_perror("radclient"); exit(1); } #if 0 { FILE *randinit; if((randinit = fopen("/dev/urandom", "r")) == NULL) { perror("/dev/urandom"); } else { fread(randctx.randrsl, 256, 1, randinit); fclose(randinit); } } fr_randinit(&randctx, 1); #endif req->id = id; /* * Resolve hostname. */ if (force_af == AF_UNSPEC) force_af = AF_INET; req->dst_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(&req->dst_ipaddr, force_af, hostname, false) < 0) { fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "auth") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_CODE_AUTHENTICATION_REQUEST; } else if (strcmp(argv[2], "acct") == 0) { if (port == 0) port = getport("radacct"); if (port == 0) port = PW_ACCT_UDP_PORT; req->code = PW_CODE_ACCOUNTING_REQUEST; do_summary = 0; } else if (strcmp(argv[2], "status") == 0) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = PW_CODE_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { if (port == 0) port = PW_POD_UDP_PORT; req->code = PW_CODE_DISCONNECT_REQUEST; } else if (isdigit((int) argv[2][0])) { if (port == 0) port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; req->code = atoi(argv[2]); } else { usage(); } req->dst_port = port; /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * Read valuepairs. * Maybe read them, from stdin, if there's no * filename, or if the filename is '-'. */ if (filename && (strcmp(filename, "-") != 0)) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", filename, fr_syserror(errno)); exit(1); } } else { fp = stdin; } /* * Send request. */ if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("radclient: socket: "); exit(1); } while(!filedone) { if (req->vps) pairfree(&req->vps); if (readvp2(&req->vps, NULL, fp, &filedone) < 0) { fr_perror("radeapclient"); break; } sendrecv_eap(req); } if(do_summary) { printf("\n\t Total approved auths: %d\n", totalapp); printf("\t Total denied auths: %d\n", totaldeny); } talloc_free(autofree); return 0; }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int status; int argval; int spawn_flag = true; int dont_fork = false; int write_pid = false; int flag = 0; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef OSFC2 set_auth_parameters(argc,argv); #endif if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; #ifdef WIN32 { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { fprintf(stderr, "%s: Unable to initialize socket library.\n", progname); return 1; } } #endif debug_flag = 0; spawn_flag = true; radius_dir = talloc_strdup(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&mainconfig, 0, sizeof(mainconfig)); mainconfig.myip.af = AF_UNSPEC; mainconfig.port = -1; mainconfig.name = "radiusd"; #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_flags = 0 ; sigemptyset( &act.sa_mask ) ; #endif /* * Don't put output anywhere until we get told a little * more. */ default_log.dest = L_DST_NULL; default_log.fd = -1; mainconfig.log_file = NULL; /* Process the options. */ while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) { switch(argval) { case 'C': check_config = true; spawn_flag = false; dont_fork = true; break; case 'd': if (radius_dir) { rad_const_free(radius_dir); } radius_dir = talloc_strdup(NULL, optarg); break; case 'D': mainconfig.dictionary_dir = talloc_strdup(NULL, optarg); break; case 'f': dont_fork = true; break; case 'h': usage(0); break; case 'l': if (strcmp(optarg, "stdout") == 0) { goto do_stdout; } mainconfig.log_file = strdup(optarg); default_log.dest = L_DST_FILES; default_log.fd = open(mainconfig.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (default_log.fd < 0) { fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, fr_syserror(errno)); exit(EXIT_FAILURE); } fr_log_fp = fdopen(default_log.fd, "a"); break; case 'i': if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) { fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg); exit(EXIT_FAILURE); } flag |= 1; break; case 'n': mainconfig.name = optarg; break; case 'm': mainconfig.debug_memory = 1; break; case 'M': memory_report = 1; mainconfig.debug_memory = 1; break; case 'p': mainconfig.port = atoi(optarg); if ((mainconfig.port <= 0) || (mainconfig.port >= 65536)) { fprintf(stderr, "radiusd: Invalid port number %s\n", optarg); exit(EXIT_FAILURE); } flag |= 2; break; case 'P': /* Force the PID to be written, even in -f mode */ write_pid = true; break; case 's': /* Single process mode */ spawn_flag = false; dont_fork = true; break; case 't': /* no child threads */ spawn_flag = false; break; case 'v': /* Don't print timestamps */ debug_flag += 2; fr_log_fp = stdout; default_log.dest = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; version(); exit(EXIT_SUCCESS); case 'X': spawn_flag = false; dont_fork = true; debug_flag += 2; mainconfig.log_auth = true; mainconfig.log_auth_badpass = true; mainconfig.log_auth_goodpass = true; do_stdout: fr_log_fp = stdout; default_log.dest = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (memory_report) { talloc_enable_null_tracking(); #ifdef WITH_VERIFY_PTR talloc_set_abort_fn(die_horribly); #endif } talloc_set_log_fn(log_talloc); /* * Mismatch between build time OpenSSL and linked SSL, * better to die here than segfault later. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (ssl_check_version() < 0) { exit(EXIT_FAILURE); } /* * Initialising OpenSSL once, here, is safer than having individual * modules do it. */ tls_global_init(); #endif if (flag && (flag != 0x03)) { fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n"); exit(EXIT_FAILURE); } if (debug_flag) { version(); } /* Read the configuration files, BEFORE doing anything else. */ if (read_mainconfig(0) < 0) { exit(EXIT_FAILURE); } #ifndef __MINGW32__ /* * Disconnect from session */ if (dont_fork == false) { pid_t pid = fork(); if (pid < 0) { ERROR("Couldn't fork: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } /* * The parent exits, so the child can run in the background. */ if (pid > 0) { exit(EXIT_SUCCESS); } #ifdef HAVE_SETSID setsid(); #endif } #endif /* * Ensure that we're using the CORRECT pid after forking, * NOT the one we started with. */ radius_pid = getpid(); /* * If we're running as a daemon, close the default file * descriptors, AFTER forking. */ if (!debug_flag) { int devnull; devnull = open("/dev/null", O_RDWR); if (devnull < 0) { ERROR("Failed opening /dev/null: %s\n", fr_syserror(errno)); exit(EXIT_FAILURE); } dup2(devnull, STDIN_FILENO); if (default_log.dest == L_DST_STDOUT) { setlinebuf(stdout); default_log.fd = STDOUT_FILENO; } else { dup2(devnull, STDOUT_FILENO); } if (default_log.dest == L_DST_STDERR) { setlinebuf(stderr); default_log.fd = STDERR_FILENO; } else { dup2(devnull, STDERR_FILENO); } close(devnull); } else { setlinebuf(stdout); /* unbuffered output */ } /* * Now we have logging check that the OpenSSL */ /* * Initialize the event pool, including threads. */ radius_event_init(mainconfig.config, spawn_flag); /* * Now that we've set everything up, we can install the signal * handlers. Before this, if we get any signal, we don't know * what to do, so we might as well do the default, and die. */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif #ifdef HAVE_SIGACTION act.sa_handler = sig_hup; sigaction(SIGHUP, &act, NULL); act.sa_handler = sig_fatal; sigaction(SIGTERM, &act, NULL); #else #ifdef SIGHUP signal(SIGHUP, sig_hup); #endif signal(SIGTERM, sig_fatal); #endif /* * If we're debugging, then a CTRL-C will cause the * server to die immediately. Use SIGTERM to shut down * the server cleanly in that case. */ if ((mainconfig.debug_memory == 1) || (debug_flag == 0)) { #ifdef HAVE_SIGACTION act.sa_handler = sig_fatal; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); #else signal(SIGINT, sig_fatal); #ifdef SIGQUIT signal(SIGQUIT, sig_fatal); #endif #endif } /* * Everything seems to have loaded OK, exit gracefully. */ if (check_config) { DEBUG("Configuration appears to be OK"); /* for -C -m|-M */ if (mainconfig.debug_memory) { goto cleanup; } exit(EXIT_SUCCESS); } #ifdef WITH_STATS radius_stats_init(0); #endif /* * Write out the PID anyway if were in foreground mode. */ if (!dont_fork) write_pid = true; /* * Only write the PID file if we're running as a daemon. * * And write it AFTER we've forked, so that we write the * correct PID. */ if (write_pid) { FILE *fp; fp = fopen(mainconfig.pid_file, "w"); if (fp != NULL) { /* * FIXME: What about following symlinks, * and having it over-write a normal file? */ fprintf(fp, "%d\n", (int) radius_pid); fclose(fp); } else { ERROR("Failed creating PID file %s: %s\n", mainconfig.pid_file, fr_syserror(errno)); exit(EXIT_FAILURE); } } exec_trigger(NULL, NULL, "server.start", false); /* * Process requests until HUP or exit. */ while ((status = radius_event_process()) == 0x80) { #ifdef WITH_STATS radius_stats_init(1); #endif hup_mainconfig(); } if (status < 0) { ERROR("Exiting due to internal error: %s", fr_strerror()); rcode = EXIT_FAILURE; } else { INFO("Exiting normally"); } exec_trigger(NULL, NULL, "server.stop", false); /* * Ignore the TERM signal: we're * about to die. */ signal(SIGTERM, SIG_IGN); /* * Send a TERM signal to all * associated processes * (including us, which gets * ignored.) */ #ifndef __MINGW32__ if (spawn_flag) kill(-radius_pid, SIGTERM); #endif /* * We're exiting, so we can delete the PID * file. (If it doesn't exist, we can ignore * the error returned by unlink) */ if (dont_fork == false) { unlink(mainconfig.pid_file); } radius_event_free(); cleanup: /* * Detach any modules. */ detach_modules(); xlat_free(); /* modules may have xlat's */ /* * Free the configuration items. */ free_mainconfig(); rad_const_free(radius_dir); #ifdef WIN32 WSACleanup(); #endif if (memory_report) { INFO("Allocated memory at time of report:"); log_talloc_report(NULL); } return rcode; }