static int _mod_conn_free(linelog_conn_t *conn) { if (shutdown(conn->sockfd, SHUT_RDWR) < 0) DEBUG3("Shutdown failed: %s", fr_syserror(errno)); if (close(conn->sockfd) < 0) DEBUG3("Closing socket failed: %s", fr_syserror(errno)); return 0; }
static void *mod_conn_create(TALLOC_CTX *ctx, void *instance) { int fd; struct sockaddr_un sa; rlm_smsotp_t *inst = instance; socklen_t socklen = sizeof(sa); int *fdp; sa.sun_family = AF_UNIX; strlcpy(sa.sun_path, inst->socket, sizeof(sa.sun_path)); fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { ERROR("Failed opening SMSOTP file %s: %s", inst->socket, fr_syserror(errno)); return NULL; } if (connect(fd, (struct sockaddr *) &sa, socklen) < -1) { ERROR("Failed connecting to SMSOTP file %s: %s", inst->socket, fr_syserror(errno)); return NULL; } fdp = talloc_zero(ctx, int); talloc_set_destructor(fdp, _mod_conn_free); *fdp = fd; return fdp; }
static int client_socket(char const *server) { int sockfd; uint16_t port; fr_ipaddr_t ipaddr; char *p, buffer[1024]; strlcpy(buffer, server, sizeof(buffer)); p = strchr(buffer, ':'); if (!p) { port = PW_RADMIN_PORT; } else { port = atoi(p + 1); *p = '\0'; } if (ip_hton(&ipaddr, AF_INET, buffer, false) < 0) { fprintf(stderr, "%s: Failed looking up host %s: %s\n", progname, buffer, fr_syserror(errno)); exit(1); } sockfd = fr_tcp_client_socket(NULL, &ipaddr, port); if (sockfd < 0) { fprintf(stderr, "%s: Failed opening socket %s: %s\n", progname, server, fr_syserror(errno)); exit(1); } return sockfd; }
/** Open a raw socket to read/write packets from/to * * @param[out] link_layer A sockaddr_ll struct to populate. Must be passed to other raw * functions. * @param[in] if_index of the interface we're binding to. * @return * - >= 0 a file descriptor to read/write packets on. * - <0 an error ocurred. */ int fr_dhcpv4_raw_socket_open(struct sockaddr_ll *link_layer, int if_index) { int fd; /* * PF_PACKET - packet interface on device level. * using a raw socket allows packet data to be unchanged by the device driver. */ fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (fd < 0) { fr_strerror_printf("Cannot open socket: %s", fr_syserror(errno)); return fd; } /* Set link layer parameters */ memset(link_layer, 0, sizeof(struct sockaddr_ll)); link_layer->sll_family = AF_PACKET; link_layer->sll_protocol = htons(ETH_P_ALL); link_layer->sll_ifindex = if_index; link_layer->sll_hatype = ARPHRD_ETHER; link_layer->sll_pkttype = PACKET_OTHERHOST; link_layer->sll_halen = 6; if (bind(fd, (struct sockaddr *)link_layer, sizeof(struct sockaddr_ll)) < 0) { close(fd); fr_strerror_printf("Cannot bind raw socket: %s", fr_syserror(errno)); return -1; } return fd; }
/* * Zap all users on a NAS from the radutmp file. */ static rlm_rcode_t radutmp_zap(REQUEST *request, char const *filename, uint32_t nasaddr, time_t t) { struct radutmp u; int fd; if (t == 0) time(&t); fd = open(filename, O_RDWR); if (fd < 0) { REDEBUG("Error accessing file %s: %s", filename, fr_syserror(errno)); return RLM_MODULE_FAIL; } /* * Lock the utmp file, prefer lockf() over flock(). */ if (rad_lockfd(fd, LOCK_LEN) < 0) { REDEBUG("Failed to acquire lock on file %s: %s", filename, fr_syserror(errno)); close(fd); return RLM_MODULE_FAIL; } /* * Find the entry for this NAS / portno combination. */ while (read(fd, &u, sizeof(u)) == sizeof(u)) { if ((nasaddr != 0 && nasaddr != u.nas_address) || u.type != P_LOGIN) { continue; } /* * Match. Zap it. */ if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) { REDEBUG("radutmp_zap: negative lseek!"); lseek(fd, (off_t)0, SEEK_SET); } u.type = P_IDLE; u.time = t; if (write(fd, &u, sizeof(u)) < 0) { REDEBUG("Failed writing: %s", fr_syserror(errno)); close(fd); return RLM_MODULE_FAIL; } } close(fd); /* and implicitely release the locks */ return RLM_MODULE_OK; }
/** Generate a talloc memory report for a context and print to stderr/stdout * * @param ctx to generate a report for, may be NULL in which case the root context is used. */ int fr_log_talloc_report(TALLOC_CTX *ctx) { #define TALLOC_REPORT_MAX_DEPTH 20 FILE *log; int fd; fd = dup(fr_fault_log_fd); if (fd < 0) { fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno)); return -1; } log = fdopen(fd, "w"); if (!log) { close(fd); fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno)); return -1; } if (!ctx) { fprintf(log, "Current state of talloced memory:\n"); talloc_report_full(talloc_null_ctx, log); } else { int i; fprintf(log, "Talloc chunk lineage:\n"); fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx)); i = 0; while ((i < TALLOC_REPORT_MAX_DEPTH) && (ctx = talloc_parent(ctx))) { fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx)); i++; } fprintf(log, "\n"); i = 0; do { fprintf(log, "Talloc context level %i:\n", i++); talloc_report_full(ctx, log); } while ((ctx = talloc_parent(ctx)) && (i < TALLOC_REPORT_MAX_DEPTH) && (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */ (talloc_parent(ctx) != talloc_null_ctx)); /* Stop before we hit NULL ctx */ } fclose(log); return 0; }
/* * Open a socket TO the given IP and port. */ int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if (!dst_ipaddr) return -1; sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0); if (sockfd < 0) { return sockfd; } /* * Allow the caller to bind us to a specific source IP. */ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) { if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) { close(sockfd); return -1; } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno)); close(sockfd); return -1; } } if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) { close(sockfd); return -1; } /* * FIXME: If EINPROGRESS, then tell the caller that * somehow. The caller can then call connect() when the * socket is ready... */ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failed in connect(): %s", fr_syserror(errno)); close(sockfd); return -1; } return sockfd; }
/** Open a detail listener * */ static int mod_open(fr_listen_t *li) { proto_detail_file_t const *inst = talloc_get_type_abort_const(li->app_io_instance, proto_detail_file_t); proto_detail_file_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_detail_file_thread_t); if (inst->poll_interval == 0) { int oflag; #ifdef O_EVTONLY oflag = O_EVTONLY; #else oflag = O_RDONLY; #endif li->fd = thread->fd = open(inst->directory, oflag); } else { li->fd = thread->fd = open("/dev/null", O_RDONLY); } if (thread->fd < 0) { cf_log_err(inst->cs, "Failed opening %s: %s", inst->directory, fr_syserror(errno)); return -1; } thread->inst = inst; thread->name = talloc_typed_asprintf(thread, "detail polling for files matching %s", inst->filename); thread->vnode_fd = -1; pthread_mutex_init(&thread->worker_mutex, NULL); DEBUG("Listening on %s bound to virtual server %s", thread->name, cf_section_name2(inst->parent->server_cs)); return 0; }
static PerlInterpreter *rlm_perl_clone(PerlInterpreter *perl, pthread_key_t *key) { int ret; PerlInterpreter *interp; UV clone_flags = 0; PERL_SET_CONTEXT(perl); interp = pthread_getspecific(*key); if (interp) return interp; interp = perl_clone(perl, clone_flags); { dTHXa(interp); } # if PERL_REVISION >= 5 && PERL_VERSION <8 call_pv("CLONE",0); # endif ptr_table_free(PL_ptr_table); PL_ptr_table = NULL; PERL_SET_CONTEXT(aTHX); rlm_perl_clear_handles(aTHX); ret = pthread_setspecific(*key, interp); if (ret != 0) { DEBUG("Failed associating interpretor with thread %s", fr_syserror(ret)); rlm_perl_destruct(interp); return NULL; } return interp; }
static void send_with_socket(RADIUS_PACKET *request) { request->sockfd = sockfd; if (fr_dhcp_send(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(reply); if (fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); fr_exit_now(1); } }
/* * Full write with logging, and close on failure. * Returns number of bytes written on success, errno on failure. */ static int otp_write(otp_fd_t *fdp, char const *buf, size_t len) { size_t nleft = len; ssize_t nwrote; while (nleft) { nwrote = write(fdp->fd, &buf[len - nleft], nleft); if (nwrote == -1) { if (errno == EINTR) { continue; } else { ERROR("rlm_otp: %s: write to otpd: %s", __func__, fr_syserror(errno)); otp_putfd(fdp, 1); return errno; } } nleft -= nwrote; } return len - nleft; }
void log_talloc_report(TALLOC_CTX *ctx) { FILE *fd; char const *null_ctx = NULL; int i = 0; if (ctx) { null_ctx = talloc_get_name(NULL); } fd = fdopen(default_log.fd, "w"); if (!fd) { ERROR("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno)); return; } if (!ctx) { talloc_report_full(NULL, fd); } else { do { INFO("Context level %i", i++); talloc_report_full(ctx, fd); } while ((ctx = talloc_parent(ctx)) && (talloc_get_name(ctx) != null_ctx)); /* Stop before we hit NULL ctx */ } fclose(fd); }
static int tls_socket_write(rad_listen_t *listener, REQUEST *request) { uint8_t *p; ssize_t rcode; listen_socket_t *sock = listener->data; p = sock->ssn->dirty_out.data; while (p < (sock->ssn->dirty_out.data + sock->ssn->dirty_out.used)) { RDEBUG3("Writing to socket %d", request->packet->sockfd); rcode = write(request->packet->sockfd, p, (sock->ssn->dirty_out.data + sock->ssn->dirty_out.used) - p); if (rcode <= 0) { RDEBUG("Error writing to TLS socket: %s", fr_syserror(errno)); tls_socket_close(listener); return 0; } p += rcode; } sock->ssn->dirty_out.used = 0; return 1; }
/* * Full read with logging, and close on failure. * Returns nread on success, 0 on EOF, -1 on other failures. */ static int otp_read(otp_fd_t *fdp, char *buf, size_t len) { ssize_t n; size_t nread = 0; /* bytes read into buf */ while (nread < len) { n = read(fdp->fd, &buf[nread], len - nread); if (n == -1) { if (errno == EINTR) { continue; } else { ERROR("rlm_otp: %s: read from otpd: %s", __func__, fr_syserror(errno)); otp_putfd(fdp, 1); return -1; } } if (!n) { ERROR("rlm_otp: %s: otpd disconnect", __func__); otp_putfd(fdp, 1); return 0; } nread += n; } /* while (more to read) */ return nread; }
/* * Log the query to a file. */ void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section, char const *query) { int fd; char const *filename = NULL; char *expanded = NULL; size_t len; bool failed = false; /* Write the log message outside of the critical region */ if (section) { filename = section->logfile; } else { filename = inst->config->logfile; } if (!filename) { return; } if (radius_axlat(&expanded, request, filename, NULL, NULL) < 0) { return; } fd = exfile_open(inst->ef, filename, 0640, true); if (fd < 0) { ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->config->xlat_name, expanded, fr_syserror(errno)); talloc_free(expanded); return; } len = strlen(query); if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) { failed = true; } if (failed) { ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->config->xlat_name, expanded, fr_syserror(errno)); } talloc_free(expanded); exfile_close(inst->ef, fd); }
/** Get the current maximum for core files * * Do this before anything else so as to ensure it's properly initialized. */ int fr_set_dumpable_init(void) { #ifdef HAVE_SYS_RESOURCE_H if (getrlimit(RLIMIT_CORE, &core_limits) < 0) { fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno)); return -1; } #endif return 0; }
static int fr_set_dumpable_flag(bool dumpable) { if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) { fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s", fr_syserror(errno)); return -1; } return 0; }
/** File descriptor experienced an error * * @param[in] el fd was registered with. * @param[in] fd that errored. * @param[in] flags from kevent. * @param[in] fd_errno from kevent. * @param[in] ctx The rlm_rest_thread_t specific to this thread. */ static void _rest_io_service_errored(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, int fd_errno, void *ctx) { rlm_rest_thread_t *t; t = talloc_get_type_abort(ctx, rlm_rest_thread_t); DEBUG4("libcurl fd %i errored: %s", fd, fr_syserror(fd_errno)); _rest_io_service(t, fd, CURL_CSELECT_ERR); }
static ssize_t date_encode_strftime(char **out, size_t outlen, rlm_date_t const *inst, REQUEST *request, time_t date) { struct tm tminfo; if (inst->utc) { if (gmtime_r(&date, &tminfo) == NULL) { REDEBUG("Failed converting time string to gmtime: %s", fr_syserror(errno)); return -1; } } else { if (localtime_r(&date, &tminfo) == NULL) { REDEBUG("Failed converting time string to localtime: %s", fr_syserror(errno)); return -1; } } return strftime(*out, outlen, inst->fmt, &tminfo); }
/** Connection errored * */ static void _logtee_conn_error(UNUSED fr_event_list_t *el, int sock, UNUSED int flags, int fd_errno, void *uctx) { rlm_logtee_thread_t *t = talloc_get_type_abort(uctx, rlm_logtee_thread_t); ERROR("Connection failed (%i): %s", sock, fr_syserror(fd_errno)); /* * Something bad happened... Fix it... */ fr_connection_signal_reconnect(t->conn); }
static void fr_set_dumpable(void) { /* * If configured, turn core dumps off. */ if (!allow_core_dumps) { #ifdef HAVE_SYS_RESOURCE_H struct rlimit no_core; no_core.rlim_cur = 0; no_core.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &no_core) < 0) { ERROR("Failed disabling core dumps: %s", fr_syserror(errno)); } #endif return; } /* * Set or re-set the dumpable flag. */ #ifdef HAVE_SYS_PRCTL_H #ifdef PR_SET_DUMPABLE if (prctl(PR_SET_DUMPABLE, 1) < 0) { ERROR("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'", fr_syserror(errno)); } #endif #endif /* * Reset the core dump limits to their original value. */ #ifdef HAVE_SYS_RESOURCE_H if (setrlimit(RLIMIT_CORE, &core_limits) < 0) { ERROR("Cannot update core dump limit: %s", fr_syserror(errno)); } #endif }
/** Guaranteed initialization * */ void _otp_pthread_mutex_init(pthread_mutex_t *mutexp, pthread_mutexattr_t const *attr, char const *caller) { int rc; rc = pthread_mutex_init(mutexp, attr); if (rc) { ERROR("rlm_otp: %s: pthread_mutex_init: %s", caller, fr_syserror(rc)); exit(1); } }
void fr_suid_down(void) { if (!uid_name) return; if (setuid(server_uid) < 0) { fprintf(stderr, "%s: Failed switching to uid %s: %s\n", progname, uid_name, fr_syserror(errno)); fr_exit_now(1); } fr_set_dumpable(allow_core_dumps); }
/** Log to thread local error buffer * * @param fmt printf style format string. If NULL sets the 'new' byte to false, * effectively clearing the last message. */ void fr_strerror_printf(char const *fmt, ...) { va_list ap; char *buffer; buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */ if (!buffer) { fr_perror("Failed allocating memory for libradius error buffer"); return; } ret = fr_thread_local_set(fr_strerror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret)); free(buffer); return; } } /* * NULL has a special meaning, setting the new bit to false. */ if (!fmt) { buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; return; } va_start(ap, fmt); /* * Alternate where we write the message, so we can do: * fr_strerror_printf("Additional error: %s", fr_strerror()); */ switch (buffer[FR_STRERROR_BUFSIZE * 2] & 0x06) { default: vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x05; /* Flip the 'new' bit to true */ break; case 0x04: vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x03; /* Flip the 'new' bit to true */ break; } va_end(ap); }
/** Guaranteed lock * */ void _otp_pthread_mutex_lock(pthread_mutex_t *mutexp, char const *caller) { int rc; rc = pthread_mutex_lock(mutexp); if (rc) { ERROR("rlm_otp: %s: pthread_mutex_lock: %s", caller, fr_syserror(rc)); exit(1); } }
/* * Log the query to a file. */ void rlm_sql_query_log(rlm_sql_t const *inst, REQUEST *request, sql_acct_section_t *section, char const *query) { int fd; char const *filename = NULL; char *expanded = NULL; size_t len; bool failed = false; /* Write the log message outside of the critical region */ filename = inst->config->logfile; if (section && section->logfile) filename = section->logfile; if (!filename || !*filename) { return; } if (xlat_aeval(request, &expanded, request, filename, NULL, NULL) < 0) { return; } fd = exfile_open(inst->ef, request, filename, 0640); if (fd < 0) { ERROR("Couldn't open logfile '%s': %s", expanded, fr_syserror(errno)); talloc_free(expanded); /* coverity[missing_unlock] */ return; } len = strlen(query); if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) { failed = true; } if (failed) ERROR("Failed writing to logfile '%s': %s", expanded, fr_syserror(errno)); talloc_free(expanded); exfile_close(inst->ef, request, fd); }
/* connect to otpd and return fd */ static int otp_connect(char const *path) { int fd; struct sockaddr_un sa; size_t sp_len; /* sun_path length (strlen) */ /* setup for unix domain socket */ sp_len = strlen(path); if (sp_len > sizeof(sa.sun_path) - 1) { ERROR("rlm_otp: %s: rendezvous point name too long", __func__); return -1; } sa.sun_family = AF_UNIX; (void) strcpy(sa.sun_path, path); /* connect to otpd */ fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd == -1) { ERROR("rlm_otp: %s: socket: %s", __func__, fr_syserror(errno)); return -1; } if (connect(fd, (struct sockaddr *) &sa, sizeof(sa.sun_family) + sp_len) == -1) { ERROR("rlm_otp: %s: connect(%s): %s", __func__, path, fr_syserror(errno)); (void) close(fd); return -1; } return fd; }
/* * Log the query to a file. */ void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section, char const *query) { int fd; char const *filename = NULL; char *expanded = NULL; if (section) { filename = section->logfile; } else { filename = inst->config->logfile; } if (!filename) { return; } if (radius_axlat(&expanded, request, filename, NULL, NULL) < 0) { return; } fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) { ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->config->xlat_name, expanded, fr_syserror(errno)); talloc_free(expanded); return; } if ((rad_lockfd(fd, MAX_QUERY_LEN) < 0) || (write(fd, query, strlen(query)) < 0) || (write(fd, ";\n", 2) < 0)) { ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->config->xlat_name, expanded, fr_syserror(errno)); } talloc_free(expanded); close(fd); /* and release the lock */ }
/** Free a control structure * * This function really only calls the underlying "garbage collect". * * @param[in] c the control structure */ void fr_control_free(fr_control_t *c) { struct kevent kev; (void) talloc_get_type_abort(c, fr_control_t); EV_SET(&kev, c->ident, EVFILT_USER, EV_DELETE, NOTE_FFNOP, 0, NULL); if (kevent(c->kq, &kev, 1, NULL, 0, NULL) < 0) { talloc_free(c); fr_strerror_printf("Failed opening KQ for control socket: %s", fr_syserror(errno)); } talloc_free(c); }
static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout) { int fd; rlm_smsotp_t *inst = instance; int *fdp; fd = fr_socket_client_unix(inst->socket, false); if (fd < 0) { ERROR("Failed opening SMSOTP file %s: %s", inst->socket, fr_syserror(errno)); return NULL; } if (fr_socket_wait_for_connect(fd, timeout) < 0) { ERROR("Failed connecting to SMSOTP file %s: %s", inst->socket, fr_syserror(errno)); return NULL; } fdp = talloc_zero(ctx, int); talloc_set_destructor(fdp, _mod_conn_free); *fdp = fd; return fdp; }