static bool pid_file_read(const char *path) { char buf[32]; int fd; ssize_t ret; pid_t pid; bool found = FALSE; fd = open(path, O_RDONLY); if (fd == -1) { if (errno != ENOENT) i_error("open(%s) failed: %m", path); return FALSE; } ret = read(fd, buf, sizeof(buf)); if (ret < 0) i_error("read(%s) failed: %m", path); else if (ret > 0 && buf[ret-1] == '\n') { buf[ret-1] = '\0'; if (str_to_pid(buf, &pid) == 0) { found = !(pid == getpid() || (kill(pid, 0) < 0 && errno == ESRCH)); } } i_close_fd(&fd); return found; }
int mail_session_connect_parse(const char *const *args, const char **error_r) { struct mail_session *session; const char *session_id; pid_t pid; struct ip_addr ip; unsigned int i; /* <session id> <username> <service> <pid> [key=value ..] */ if (str_array_length(args) < 4) { *error_r = "CONNECT: Too few parameters"; return -1; } session_id = args[0]; if (str_to_pid(args[3], &pid) < 0) { *error_r = t_strdup_printf("CONNECT: Invalid pid %s for session ID %s", args[3], session_id); return -1; } session = hash_table_lookup(mail_sessions_hash, session_id); if (session != NULL) { *error_r = t_strdup_printf( "CONNECT: Duplicate session ID %s for user %s service %s", session_id, args[1], args[2]); return -1; } session = i_malloc(sizeof(struct mail_session) + stats_alloc_size()); session->stats = (void *)(session + 1); session->refcount = 1; /* unrefed at disconnect */ session->id = i_strdup(session_id); session->service = str_table_ref(services, args[2]); session->pid = pid; session->last_update = ioloop_timeval; session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS, mail_session_idle_timeout, session); session->user = mail_user_login(args[1]); for (i = 3; args[i] != NULL; i++) { if (strncmp(args[i], "rip=", 4) == 0 && net_addr2ip(args[i] + 4, &ip) == 0) session->ip = mail_ip_login(&ip); } hash_table_insert(mail_sessions_hash, session->id, session); DLLIST_PREPEND_FULL(&stable_mail_sessions, session, stable_prev, stable_next); DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session, sorted_prev, sorted_next); DLLIST_PREPEND_FULL(&session->user->sessions, session, user_prev, user_next); mail_user_ref(session->user); if (session->ip != NULL) { DLLIST_PREPEND_FULL(&session->ip->sessions, session, ip_prev, ip_next); mail_ip_ref(session->ip); } global_memory_alloc(mail_session_memsize(session)); return 0; }
static bool pid_file_read(const char *path, pid_t *pid_r) { char buf[32]; int fd; ssize_t ret; bool found; fd = open(path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) return FALSE; i_fatal("open(%s) failed: %m", path); } ret = read(fd, buf, sizeof(buf)-1); if (ret <= 0) { if (ret == 0) i_error("Empty PID file in %s", path); else i_fatal("read(%s) failed: %m", path); found = FALSE; } else { if (buf[ret-1] == '\n') ret--; buf[ret] = '\0'; if (str_to_pid(buf, pid_r) < 0) found = FALSE; else { found = !(*pid_r == getpid() || (kill(*pid_r, 0) < 0 && errno == ESRCH)); } } i_close_fd(&fd); return found; }
static const char * file_lock_find_proc_locks(int lock_fd ATTR_UNUSED) { /* do anything except Linux support this? don't bother trying it for OSes we don't know about. */ #ifdef __linux__ static bool have_proc_locks = TRUE; struct stat st; char node_buf[MAX_INT_STRLEN*3 + 2 + 1]; struct istream *input; const char *line, *lock_type = ""; pid_t pid = 0; int fd; if (!have_proc_locks) return FALSE; if (fstat(lock_fd, &st) < 0) return ""; i_snprintf(node_buf, sizeof(node_buf), "%02x:%02x:%llu", major(st.st_dev), minor(st.st_dev), (unsigned long long)st.st_ino); fd = open("/proc/locks", O_RDONLY); if (fd == -1) { have_proc_locks = FALSE; return ""; } input = i_stream_create_fd_autoclose(&fd, 512); while (pid == 0 && (line = i_stream_read_next_line(input)) != NULL) T_BEGIN { const char *const *args = t_strsplit_spaces(line, " "); /* number: FLOCK/POSIX ADVISORY READ/WRITE pid major:minor:inode region-start region-end */ if (str_array_length(args) < 8) continue; if (strcmp(args[5], node_buf) == 0) { lock_type = strcmp(args[3], "READ") == 0 ? "READ" : "WRITE"; if (str_to_pid(args[4], &pid) < 0) pid = 0; } } T_END; i_stream_destroy(&input); if (pid == 0) { /* not found */ return ""; } if (pid == getpid()) return " (BUG: lock is held by our own process)"; return t_strdup_printf(" (%s lock held by pid %ld)", lock_type, (long)pid); #else return ""; #endif }
static void master_login_auth_input(struct master_login_auth *auth) { const char *line; bool ret; switch (i_stream_read(auth->input)) { case 0: return; case -1: /* disconnected. stop accepting new connections, because in default configuration we no longer have permissions to connect back to auth-master */ master_service_stop_new_connections(master_service); master_login_auth_disconnect(auth); return; case -2: /* buffer full */ i_error("Auth server sent us too long line"); master_login_auth_disconnect(auth); return; } if (!auth->version_received) { line = i_stream_next_line(auth->input); if (line == NULL) return; /* make sure the major version matches */ if (strncmp(line, "VERSION\t", 8) != 0 || !str_uint_equals(t_strcut(line + 8, '\t'), AUTH_MASTER_PROTOCOL_MAJOR_VERSION)) { i_error("Authentication server not compatible with " "master process (mixed old and new binaries?)"); master_login_auth_disconnect(auth); return; } auth->version_received = TRUE; } if (!auth->spid_received) { line = i_stream_next_line(auth->input); if (line == NULL) return; if (strncmp(line, "SPID\t", 5) != 0 || str_to_pid(line + 5, &auth->auth_server_pid) < 0) { i_error("Authentication server didn't " "send valid SPID as expected: %s", line); master_login_auth_disconnect(auth); return; } auth->spid_received = TRUE; master_login_auth_check_spids(auth); } auth->refcount++; while ((line = i_stream_next_line(auth->input)) != NULL) { if (strncmp(line, "USER\t", 5) == 0) ret = master_login_auth_input_user(auth, line + 5); else if (strncmp(line, "NOTFOUND\t", 9) == 0) ret = master_login_auth_input_notfound(auth, line + 9); else if (strncmp(line, "FAIL\t", 5) == 0) ret = master_login_auth_input_fail(auth, line + 5); else ret = TRUE; if (!ret || auth->input == NULL) { master_login_auth_disconnect(auth); break; } } master_login_auth_unref(&auth); }
int mail_session_connect_parse(const char *const *args, const char **error_r) { struct mail_session *session; guid_128_t session_guid; uint8_t *guid_p; pid_t pid; struct ip_addr ip; unsigned int i; /* <session guid> <username> <service> <pid> [key=value ..] */ if (str_array_length(args) < 4) { *error_r = "CONNECT: Too few parameters"; return -1; } if (guid_128_from_string(args[0], session_guid) < 0) { *error_r = "CONNECT: Invalid GUID"; return -1; } if (str_to_pid(args[3], &pid) < 0) { *error_r = "CONNECT: Invalid pid"; return -1; } guid_p = session_guid; session = hash_table_lookup(mail_sessions_hash, guid_p); if (session != NULL) { *error_r = "CONNECT: Duplicate session GUID"; return -1; } session = i_new(struct mail_session, 1); session->refcount = 1; /* unrefed at disconnect */ session->service = i_strdup(args[2]); memcpy(session->guid, session_guid, sizeof(session->guid)); session->pid = pid; session->last_update = ioloop_timeval; session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS, mail_session_idle_timeout, session); session->user = mail_user_login(args[1]); for (i = 3; args[i] != NULL; i++) { if (strncmp(args[i], "rip=", 4) == 0 && net_addr2ip(args[i] + 4, &ip) == 0) session->ip = mail_ip_login(&ip); } guid_p = session->guid; hash_table_insert(mail_sessions_hash, guid_p, session); DLLIST_PREPEND_FULL(&stable_mail_sessions, session, stable_prev, stable_next); DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session, sorted_prev, sorted_next); DLLIST_PREPEND_FULL(&session->user->sessions, session, user_prev, user_next); mail_user_ref(session->user); if (session->ip != NULL) { DLLIST_PREPEND_FULL(&session->ip->sessions, session, ip_prev, ip_next); mail_ip_ref(session->ip); } global_memory_alloc(mail_session_memsize(session)); return 0; }