static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *request) { int fd = -1; rlm_linelog_t *inst = (rlm_linelog_t*) instance; char const *value = inst->line; #ifdef HAVE_GRP_H gid_t gid; char *endptr; #endif char path[2048]; char line[4096]; line[0] = '\0'; if (inst->reference) { CONF_ITEM *ci; CONF_PAIR *cp; if (radius_xlat(line + 1, sizeof(line) - 1, request, inst->reference, linelog_escape_func, NULL) < 0) { return RLM_MODULE_FAIL; } line[0] = '.'; /* force to be in current section */ /* * Don't allow it to go back up */ if (line[1] == '.') goto do_log; ci = cf_reference_item(NULL, inst->cs, line); if (!ci) { RDEBUG2("No such entry \"%s\"", line); return RLM_MODULE_NOOP; } if (!cf_item_is_pair(ci)) { RDEBUG2("Entry \"%s\" is not a variable assignment ", line); goto do_log; } cp = cf_item_to_pair(ci); value = cf_pair_value(cp); if (!value) { RWDEBUG2("Entry \"%s\" has no value", line); return RLM_MODULE_OK; } /* * Value exists, but is empty. Don't log anything. */ if (!*value) return RLM_MODULE_OK; } do_log: /* * FIXME: Check length. */ if (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0) { return RLM_MODULE_FAIL; } #ifdef HAVE_SYSLOG_H if (strcmp(inst->filename, "syslog") == 0) { syslog(inst->syslog_priority, "%s", line); return RLM_MODULE_OK; } #endif /* * We're using a real filename now. */ if (radius_xlat(path, sizeof(path), request, inst->filename, inst->escape_func, NULL) < 0) { return RLM_MODULE_FAIL; } fd = exfile_open(inst->ef, path, inst->permissions, true); if (fd < 0) { ERROR("rlm_linelog: Failed to open %s: %s", path, fr_syserror(errno)); return RLM_MODULE_FAIL; } if (inst->group != NULL) { gid = strtol(inst->group, &endptr, 10); if (*endptr != '\0') { if (rad_getgid(request, &gid, inst->group) < 0) { RDEBUG2("Unable to find system group \"%s\"", inst->group); goto skip_group; } } if (chown(path, -1, gid) == -1) { RDEBUG2("Unable to change system group of \"%s\"", path); } } skip_group: strcat(line, "\n"); if (write(fd, line, strlen(line)) < 0) { exfile_close(inst->ef, fd); ERROR("rlm_linelog: Failed writing: %s", fr_syserror(errno)); return RLM_MODULE_FAIL; } exfile_close(inst->ef, fd); return RLM_MODULE_OK; }
/* * Instantiate the module. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { linelog_instance_t *inst = instance; char prefix[100]; /* * Escape filenames only if asked. */ if (inst->file.escape) { inst->file.escape_func = rad_filename_escape; } else { inst->file.escape_func = rad_filename_make_safe; } inst->log_dst = fr_str2int(linelog_dst_table, inst->log_dst_str, LINELOG_DST_INVALID); if (inst->log_dst == LINELOG_DST_INVALID) { cf_log_err_cs(conf, "Invalid log destination \"%s\"", inst->log_dst_str); return -1; } if (!inst->log_src && !inst->log_ref) { cf_log_err_cs(conf, "Must specify a log format, or reference"); return -1; } inst->name = cf_section_name2(conf); if (!inst->name) inst->name = cf_section_name1(conf); snprintf(prefix, sizeof(prefix), "rlm_linelog (%s)", inst->name); /* * Setup the logging destination */ switch (inst->log_dst) { case LINELOG_DST_FILE: { if (!inst->file.name) { cf_log_err_cs(conf, "No value provided for 'filename'"); return -1; } inst->file.ef = exfile_init(inst, 64, 30, true); if (!inst->file.ef) { cf_log_err_cs(conf, "Failed creating log file context"); return -1; } if (inst->file.group_str) { char *endptr; inst->file.group = strtol(inst->file.group_str, &endptr, 10); if (*endptr != '\0') { if (rad_getgid(inst, &(inst->file.group), inst->file.group_str) < 0) { cf_log_err_cs(conf, "Unable to find system group \"%s\"", inst->file.group_str); return -1; } } } } break; case LINELOG_DST_SYSLOG: { int num; #ifndef HAVE_SYSLOG_H cf_log_err_cs(conf, "Syslog output is not supported on this system"); return -1; #else if (inst->syslog.facility) { num = fr_str2int(syslog_facility_table, inst->syslog.facility, -1); if (num < 0) { cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog.facility); return -1; } inst->syslog.priority |= num; } num = fr_str2int(syslog_severity_table, inst->syslog.severity, -1); if (num < 0) { cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog.severity); return -1; } inst->syslog.priority |= num; #endif } break; case LINELOG_DST_UNIX: #ifndef HAVE_SYS_UN_H cf_log_err_cs(conf, "Unix sockets are not supported on this sytem"); return -1; #else inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "unix"), inst, mod_conn_create, NULL, prefix); if (!inst->pool) return -1; #endif break; case LINELOG_DST_UDP: inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "udp"), inst, mod_conn_create, NULL, prefix); if (!inst->pool) return -1; break; case LINELOG_DST_TCP: inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "tcp"), inst, mod_conn_create, NULL, prefix); if (!inst->pool) return -1; break; case LINELOG_DST_INVALID: rad_assert(0); break; } inst->delimiter_len = talloc_array_length(inst->delimiter) - 1; inst->cs = conf; return 0; }
/* * Do detail, compatible with old accounting */ static rlm_rcode_t CC_HINT(nonnull) detail_do(void *instance, REQUEST *request, RADIUS_PACKET *packet, bool compat) { int outfd; char buffer[DIRLEN]; FILE *outfp; #ifdef HAVE_GRP_H gid_t gid; char *endptr; #endif detail_instance_t *inst = instance; /* * Generate the path for the detail file. Use the same * format, but truncate at the last /. Then feed it * through radius_xlat() to expand the variables. */ if (radius_xlat(buffer, sizeof(buffer), request, inst->filename, inst->escape_func, NULL) < 0) { return RLM_MODULE_FAIL; } RDEBUG2("%s expands to %s", inst->filename, buffer); #ifdef WITH_ACCOUNTING #if defined(HAVE_FNMATCH_H) && defined(FNM_FILE_NAME) /* * If we read it from a detail file, and we're about to * write it back to the SAME detail file directory, then * suppress the write. This check prevents an infinite * loop. */ if ((request->listener->type == RAD_LISTEN_DETAIL) && (fnmatch(((listen_detail_t *)request->listener->data)->filename, buffer, FNM_FILE_NAME | FNM_PERIOD ) == 0)) { RWDEBUG2("Suppressing infinite loop"); return RLM_MODULE_NOOP; } #endif #endif outfd = exfile_open(inst->ef, buffer, inst->perm, true); if (outfd < 0) { RERROR("Couldn't open file %s: %s", buffer, fr_strerror()); return RLM_MODULE_FAIL; } if (inst->group != NULL) { gid = strtol(inst->group, &endptr, 10); if (*endptr != '\0') { if (rad_getgid(request, &gid, inst->group) < 0) { RDEBUG2("Unable to find system group '%s'", inst->group); goto skip_group; } } if (chown(buffer, -1, gid) == -1) { RDEBUG2("Unable to change system group of '%s'", buffer); } } skip_group: /* * Open the output fp for buffering. */ if ((outfp = fdopen(outfd, "a")) == NULL) { RERROR("Couldn't open file %s: %s", buffer, fr_syserror(errno)); fail: if (outfp) fclose(outfp); exfile_unlock(inst->ef, outfd); return RLM_MODULE_FAIL; } if (detail_write(outfp, inst, request, packet, compat) < 0) goto fail; /* * Flush everything */ fclose(outfp); exfile_unlock(inst->ef, outfd); /* do NOT close outfp */ /* * And everything is fine. */ return RLM_MODULE_OK; }