int mu_progmailer_open (struct _mu_progmailer *pm, char **argv) { int tunnel[2]; int status = 0; int i; if (!pm || !argv) return EINVAL; if ((pm->sighandler = signal (SIGCHLD, SIG_DFL)) == SIG_ERR) { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("setting SIGCHLD failed: %s", mu_strerror (status))); return status; } if (pipe (tunnel) == 0) { pm->fd = tunnel[1]; pm->pid = fork (); if (pm->pid == 0) /* Child. */ { SCLOSE (STDIN_FILENO, tunnel); SCLOSE (STDOUT_FILENO, tunnel); SCLOSE (STDERR_FILENO, tunnel); close (tunnel[1]); dup2 (tunnel[0], STDIN_FILENO); execv (pm->command ? pm->command : argv[0], argv); exit (errno ? EX_CANTCREAT : 0); } else if (pm->pid == -1) { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("fork failed: %s", mu_strerror (status))); } } else { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("pipe() failed: %s\n", mu_strerror (status))); } if (mu_debug_level_p (MU_DEBCAT_MAILER, 10)) { mu_debug_log_begin ("exec %s argv:", pm->command); for (i = 0; argv[i]; i++) mu_debug_log_cont (" %s", argv[i]); mu_debug_log_nl (); } close (tunnel[0]); if (status != 0) close (pm->fd); return status; }
void xdebug_close_socket(int socket) { SCLOSE(socket); }
/** Sends a request to a RADIUS server and waits for the reply * * @param rh a handle to parsed configuration * @param ctx if non-NULL it will contain the context of sent request; It must be released using rc_aaa_ctx_free(). * @param data a pointer to a SEND_DATA structure * @param msg must be an array of %PW_MAX_MSG_SIZE or NULL; will contain the concatenation of * any %PW_REPLY_MESSAGE received. * @param type must be %AUTH or %ACCT * @return OK_RC (0) on success, TIMEOUT_RC on timeout REJECT_RC on acess reject, or negative * on failure as return value. */ int rc_send_server_ctx(rc_handle * rh, RC_AAA_CTX ** ctx, SEND_DATA * data, char *msg, rc_type type) { int sockfd = -1; AUTH_HDR *auth, *recv_auth; char *server_name, *p; /* Name of server to query */ struct sockaddr_storage our_sockaddr; struct addrinfo *auth_addr = NULL; socklen_t salen; int result = 0; int total_length; int length, pos; int retry_max; const rc_sockets_override *sfuncs; unsigned discover_local_ip; size_t secretlen; char secret[MAX_SECRET_LENGTH + 1]; unsigned char vector[AUTH_VECTOR_LEN]; uint8_t recv_buffer[BUFFER_LEN]; uint8_t send_buffer[BUFFER_LEN]; uint8_t *attr; int retries; VALUE_PAIR *vp; struct pollfd pfd; double start_time, timeout; struct sockaddr_storage *ss_set = NULL; char *server_type = "auth"; server_name = data->server; if (server_name == NULL || server_name[0] == '\0') return ERROR_RC; if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && (vp->lvalue == PW_ADMINISTRATIVE)) { strcpy(secret, MGMT_POLL_SECRET); auth_addr = rc_getaddrinfo(server_name, type == AUTH ? PW_AI_AUTH : PW_AI_ACCT); if (auth_addr == NULL) return ERROR_RC; } else { if (data->secret != NULL) { strlcpy(secret, data->secret, MAX_SECRET_LENGTH); } /* else { */ if (rc_find_server_addr (rh, server_name, &auth_addr, secret, type) != 0) { rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name); return ERROR_RC; } /*} */ } sfuncs = &rh->so; if (sfuncs->static_secret) { /* any static secret set in sfuncs overrides the configured */ strlcpy(secret, sfuncs->static_secret, MAX_SECRET_LENGTH); } if (sfuncs->lock) { if (sfuncs->lock(sfuncs->ptr) != 0) { rc_log(LOG_ERR, "%s: lock error", __func__); return ERROR_RC; } } rc_own_bind_addr(rh, &our_sockaddr); discover_local_ip = 0; if (our_sockaddr.ss_family == AF_INET) { if (((struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr == INADDR_ANY) { discover_local_ip = 1; } } DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name); if (discover_local_ip) { result = rc_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr); if (result != 0) { memset(secret, '\0', sizeof(secret)); rc_log(LOG_ERR, "rc_send_server: cannot figure our own address"); result = ERROR_RC; goto cleanup; } } if (sfuncs->get_fd) { sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr)); if (sockfd < 0) { memset(secret, '\0', sizeof(secret)); rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno)); result = ERROR_RC; goto cleanup; } } retry_max = data->retries; /* Max. numbers to try for reply */ retries = 0; /* Init retry cnt for blocking call */ if (data->svc_port) { if (our_sockaddr.ss_family == AF_INET) ((struct sockaddr_in *)auth_addr->ai_addr)->sin_port = htons((unsigned short)data->svc_port); else ((struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port = htons((unsigned short)data->svc_port); } /* * Fill in NAS-IP-Address (if needed) */ if (rh->nas_addr_set) { rc_avpair_remove(&(data->send_pairs), PW_NAS_IP_ADDRESS, 0); rc_avpair_remove(&(data->send_pairs), PW_NAS_IPV6_ADDRESS, 0); ss_set = &rh->nas_addr; } else if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL && rc_avpair_get(data->send_pairs, PW_NAS_IPV6_ADDRESS, 0) == NULL) { ss_set = &our_sockaddr; } if (ss_set) { if (ss_set->ss_family == AF_INET) { uint32_t ip; ip = *((uint32_t *) (&((struct sockaddr_in *)ss_set)-> sin_addr)); ip = ntohl(ip); rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS, &ip, 0, 0); } else { void *p; p = &((struct sockaddr_in6 *)ss_set)->sin6_addr; rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IPV6_ADDRESS, p, 16, 0); } } /* * Fill in NAS-Identifier (if needed) */ p = rc_conf_str(rh, "nas-identifier"); if (p != NULL) { rc_avpair_remove(&(data->send_pairs), PW_NAS_IDENTIFIER, 0); rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IDENTIFIER, p, -1, 0); } /* Build a request */ auth = (AUTH_HDR *) send_buffer; auth->code = data->code; auth->id = data->seq_nbr; if (data->code == PW_ACCOUNTING_REQUEST) { server_type = "acct"; total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; auth->length = htons((unsigned short)total_length); memset((char *)auth->vector, 0, AUTH_VECTOR_LEN); secretlen = strlen(secret); memcpy((char *)auth + total_length, secret, secretlen); rc_md5_calc(vector, (unsigned char *)auth, total_length + secretlen); memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN); } else { rc_random_vector(vector); memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN); total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; auth->length = htons((unsigned short)total_length); } if (radcli_debug) { char our_addr_txt[50] = ""; /* hold a text IP */ char auth_addr_txt[50] = ""; /* hold a text IP */ getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0, our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST); getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0, auth_addr_txt, sizeof(auth_addr_txt), NI_NUMERICHOST); DEBUG(LOG_ERR, "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n", data->timeout, retry_max, our_addr_txt, auth_addr_txt, data->svc_port); } for (;;) { do { result = sfuncs->sendto(sfuncs->ptr, sockfd, (char *)auth, (unsigned int)total_length, (int)0, SA(auth_addr->ai_addr), auth_addr->ai_addrlen); } while (result == -1 && errno == EINTR); if (result == -1) { rc_log(LOG_ERR, "%s: socket: %s", __FUNCTION__, strerror(errno)); result = ERROR_RC; goto cleanup; } pfd.fd = sockfd; pfd.events = POLLIN; pfd.revents = 0; start_time = rc_getmtime(); for (timeout = data->timeout; timeout > 0; timeout -= rc_getmtime() - start_time) { result = poll(&pfd, 1, timeout * 1000); if (result != -1 || errno != EINTR) break; } if (result == -1) { rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno)); memset(secret, '\0', sizeof(secret)); SCLOSE(sockfd); result = ERROR_RC; goto cleanup; } if (result == 1 && (pfd.revents & POLLIN) != 0) { salen = auth_addr->ai_addrlen; do { length = sfuncs->recvfrom(sfuncs->ptr, sockfd, (char *)recv_buffer, (int) sizeof(recv_buffer), (int)0, SA(auth_addr-> ai_addr), &salen); } while (length == -1 && errno == EINTR); if (length <= 0) { int e = errno; rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name, data->svc_port, strerror(e)); if (length == -1 && (e == EAGAIN || e == EINTR)) continue; SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } recv_auth = (AUTH_HDR *) recv_buffer; if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } result = rc_check_reply(recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr); if (result != BADRESPID_RC) { /* if a message that doesn't match our ID was received, then ignore * it, and try to receive more, until timeout. That is because in * DTLS the channel is shared, and we may receive duplicates or * out-of-order packets. */ break; } } /* * Timed out waiting for response. Retry "retry_max" times * before giving up. If retry_max = 0, don't retry at all. */ if (retries++ >= retry_max) { char radius_server_ip[128]; struct sockaddr_in *si = (struct sockaddr_in *)auth_addr->ai_addr; inet_ntop(auth_addr->ai_family, &si->sin_addr, radius_server_ip, sizeof(radius_server_ip)); rc_log(LOG_ERR, "rc_send_server: no reply from RADIUS %s server %s:%u", server_type, radius_server_ip, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = TIMEOUT_RC; goto cleanup; } } /* * If UDP is larger than RADIUS, shorten it to RADIUS. */ if (length > ntohs(recv_auth->length)) length = ntohs(recv_auth->length); /* * Verify that it's a valid RADIUS packet before doing ANYTHING with it. */ attr = recv_buffer + AUTH_HDR_LEN; while (attr < (recv_buffer + length)) { if (attr[0] == 0) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute zero is invalid", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } if (attr[1] < 2) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute length is too small", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } if ((attr + attr[1]) > (recv_buffer + length)) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute overflows the packet", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } attr += attr[1]; } length = ntohs(recv_auth->length) - AUTH_HDR_LEN; if (length > 0) { data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data, length, 0); } else { data->receive_pairs = NULL; } SCLOSE(sockfd); result = populate_ctx(ctx, secret, vector); if (result != OK_RC) { memset(secret, '\0', sizeof(secret)); goto cleanup; } memset(secret, '\0', sizeof(secret)); if (msg) { *msg = '\0'; pos = 0; vp = data->receive_pairs; while (vp) { if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) { strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue); strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n"); vp = vp->next; } } } if ((recv_auth->code == PW_ACCESS_ACCEPT) || (recv_auth->code == PW_PASSWORD_ACK) || (recv_auth->code == PW_ACCOUNTING_RESPONSE)) { result = OK_RC; } else if ((recv_auth->code == PW_ACCESS_REJECT) || (recv_auth->code == PW_PASSWORD_REJECT)) { result = REJECT_RC; } else { rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, invalid"); result = BADRESP_RC; } cleanup: if (auth_addr) freeaddrinfo(auth_addr); if (sfuncs->unlock) { if (sfuncs->unlock(sfuncs->ptr) != 0) { rc_log(LOG_ERR, "%s: unlock error", __func__); } } return result; }