From: thib Date: Sun, 31 Mar 2002 15:06:19 +0000 (+0000) Subject: limit number of authentification failures X-Git-Tag: ver1564~92 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ad7b951d0af8c1f0adf3beda33203d39b62e0e9e;p=fcron limit number of authentification failures bug corrected and improvements in exe_cmd --- diff --git a/socket.c b/socket.c index 7c1ce77..0c29765 100644 --- a/socket.c +++ b/socket.c @@ -21,7 +21,7 @@ * `LICENSE' that comes with the fcron source distribution. */ - /* $Id: socket.c,v 1.1 2002-03-02 17:29:43 thib Exp $ */ + /* $Id: socket.c,v 1.2 2002-03-31 15:06:19 thib Exp $ */ /* This file contains all fcron's code (server) to handle communication with fcrondyn */ @@ -31,14 +31,17 @@ void exe_cmd(struct fcrondyn_cl *client); void auth_client(struct fcrondyn_cl *client); +int print_fields(int fd, char print_user, char print_details); +int print_line(int fd, struct CL *line, char print_user, char print_details); fcrondyn_cl *fcrondyn_cl_base; /* list of connected fcrondyn clients */ int fcrondyn_cl_num = 0; /* number of fcrondyn clients currently connected */ fd_set read_set; /* client fds list : cmd waiting ? */ fd_set master_set; /* master set : needed since select() modify read_set */ int set_max_fd = 0; /* needed by select() */ -int listen_fd = -1; /* fd which catches incoming connection */ - +int listen_fd = -1; /* fd which catches incoming connection */ +int auth_fail = 0; /* number of auth failure */ +time_t auth_nofail_since = 0; /* we refuse auth since x due to too many failures */ void init_socket(void) @@ -49,6 +52,7 @@ init_socket(void) /* used in fcron.c:main_loop():select() */ FD_ZERO(&read_set); + FD_ZERO(&master_set); if ( (listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1 ) { error_e("Could not create socket : fcrondyn won't work"); @@ -126,6 +130,22 @@ auth_client(struct fcrondyn_cl *client) pass_sys = pass->pw_passwd; #endif + /* */ + debug("auth_client() : socket : %d", client->fcl_sock_fd); + /* */ + + /* we need to limit auth failures : otherwise fcron may be used to "read" + * shadow password !!! (or to crack it using a test-all-possible-password attack) */ + if (auth_fail > 0 && auth_nofail_since + AUTH_WAIT <= now ) + /* no auth time exceeded : set counter to 0 */ + auth_fail = 0; + if (auth_fail >= MAX_AUTH_FAIL) { + error("Too many authentication failures : try to connect later."); + send(client->fcl_sock_fd, "0", sizeof("0"), 0); + auth_fail = auth_nofail_since = 0; + return; + } + /* password is stored after user name */ pass_str = &( (char *)client->fcl_cmd ) [ strlen( (char*)client->fcl_cmd ) + 1 ]; if ( (pass_cry = crypt(pass_str, pass_sys)) == NULL ) { @@ -141,6 +161,8 @@ auth_client(struct fcrondyn_cl *client) send(client->fcl_sock_fd, "1", sizeof("1"), 0); } else { + auth_fail++; + auth_nofail_since = now; error("Invalid passwd for %s from socket %d", (char *) client->fcl_cmd, client->fcl_sock_fd); send(client->fcl_sock_fd, "0", sizeof("0"), 0); @@ -148,56 +170,133 @@ auth_client(struct fcrondyn_cl *client) } + +int +print_fields(int fd, char print_user, char print_details) + /* print a line describing the field types used in print_line() */ +{ + char fields[] = " USER ID SCHEDULE CMD\n"; + char fields_details[] = " USER ID R&Q SCHEDULE CMD\n"; + char *str = NULL; + int len = 0; + + str = (print_details) ? fields_details : fields; + len = (print_details) ? sizeof(fields_details) : sizeof(fields); + if ( ! print_user ) { + str += 7; + len -= 7; + } + + if ( send(fd, str, len, 0) < 0 ) + error_e("error in send()"); + + return OK; +} + + +int +print_line(int fd, struct CL *line, char print_user, char print_details) + /* print some basic fields of a line, and some more if details == 1 */ +{ + char buf[LINE_LEN]; + int len = 0; + struct tm *ftime; + + + ftime = localtime( &(line->cl_nextexe) ); + len = snprintf(buf, sizeof(buf), "%*s%s%-4ld ", + (print_user) ? 6 : 0, (print_user) ? line->cl_file->cf_user : "", + (print_user) ? " " : "", + line->cl_id); + if (print_details) + len += snprintf(buf+len, sizeof(buf)-len, "%4d ", line->cl_numexe); + len += snprintf(buf+len, sizeof(buf)-len, "%02d/%02d/%d %02d:%02d %s\n", + (ftime->tm_mon + 1), ftime->tm_mday, (ftime->tm_year + 1900), + ftime->tm_hour, ftime->tm_min, + line->cl_shell); + + if ( send(fd, buf, len + 1, 0) < 0 ) + error_e("error in send()"); + + return OK; + +} + + void exe_cmd(struct fcrondyn_cl *client) /* read command, and call corresponding function */ { - char buf[LINE_LEN]; - int len = 0; + long int *cmd; + int fd; + char not_found_str[] = "No corresponding job found.\n"; + char not_allowed_str[] = "You are not allowed to see/change this line.\n"; + char cmd_unknown_str[] = "Not implemented yet or erroneous command.\n"; + char details = 0; + char found = 0; + char is_root = 0; + + /* to make seems clearer (avoid repeating client->fcl_ all the time */ + cmd = client->fcl_cmd; + fd = client->fcl_sock_fd; + + /* */ + debug("exe_cmd [0,1,2] : %d %d %d", cmd[0], cmd[1], cmd[2]); + /* */ switch ( client->fcl_cmd[0] ) { + case CMD_DETAILS: + details = 1; case CMD_LIST_JOBS: { struct job *j; - debug("client->fcl_cmd[1,2,3] : %d %d %d", client->fcl_cmd[0], client->fcl_cmd[1], client->fcl_cmd[2]); - if ( client->fcl_cmd[1] == ALL && strcmp(client->fcl_user, ROOTNAME) != 0) { + char all = (client->fcl_cmd[1] == ALL) ? 1 : 0; + + is_root = (strcmp(client->fcl_user, ROOTNAME) == 0) ? 1 : 0; + if ( all && ! is_root) { warn("User %s tried to list *all* jobs.", client->fcl_user); - send(client->fcl_sock_fd, "you are not allowed to list all jobs.\n", + send(fd, "you are not allowed to list all jobs.\n", sizeof("you are not allowed to list all jobs.\n"), 0); - send(client->fcl_sock_fd, END_STR, sizeof(END_STR), 0); + send(fd, END_STR, sizeof(END_STR), 0); return; } - send(client->fcl_sock_fd, "Listing jobs :\n", sizeof("Listing jobs :\n"), 0); - send(client->fcl_sock_fd, "ID\tCMD\t\n", sizeof("ID\tCMD\t\n"), 0); - for ( j = queue_base; j != NULL; j = j->j_next ) { - if ( client->fcl_cmd[1] == ALL || - strcmp(client->fcl_user, j->j_line->cl_file->cf_user) == 0 ) { - len = snprintf(buf, sizeof(buf), "%ld job: %s\n", j->j_line->cl_id, j->j_line->cl_shell); - send(client->fcl_sock_fd, buf, len + 1, 0); + print_fields(fd, details ? 1 : all, details); + if ( details ) { + for ( j = queue_base; j != NULL; j = j->j_next ) { + if ( client->fcl_cmd[1] == j->j_line->cl_id ) { + if (strcmp(client->fcl_user, j->j_line->cl_file->cf_user) == 0 + || is_root ) + print_line(fd, j->j_line, 1, 1); + else + send(fd, not_allowed_str, sizeof(not_allowed_str), 0); + found = 1; + break; + } } } + else + for ( j = queue_base; j != NULL; j = j->j_next ) { + if (all || strcmp(client->fcl_user, j->j_line->cl_file->cf_user) == 0 ) { + print_line(fd, j->j_line, all, 0); + found = 1; + } + } + if ( ! found ) + send(fd, not_found_str, sizeof(not_found_str), 0); /* to tell fcrondyn there's no more data to wait */ - send(client->fcl_sock_fd, END_STR, sizeof(END_STR), 0); + send(fd, END_STR, sizeof(END_STR), 0); } break; - + default: - { - - bzero(buf, sizeof(buf)); - len = snprintf(buf, sizeof(buf), "From exe_cmd() : Hello %s !!\n", - client->fcl_user); - debug("From exe_cmd() : Hello %s !!", client->fcl_user); - send(client->fcl_sock_fd, buf, len + 1, 0); - len = snprintf(buf, sizeof(buf), "How are you doing ?\n"); - send(client->fcl_sock_fd, buf, len + 1, 0); - + send(fd, cmd_unknown_str, sizeof(cmd_unknown_str), 0); + /* to tell fcrondyn there's no more data to wait */ - send(client->fcl_sock_fd, END_STR, sizeof(END_STR), 0); - } + send(fd, END_STR, sizeof(END_STR), 0); } } + void check_socket(int num) /* check for new connection, command, connection closed */ @@ -252,7 +351,7 @@ check_socket(int num) client = fcrondyn_cl_base; while ( client != NULL ) { - if ( ! FD_ISSET(client->fcl_sock_fd, &read_set) || client->fcl_sock_fd==avoid_fd){ + if (! FD_ISSET(client->fcl_sock_fd, &read_set) || client->fcl_sock_fd==avoid_fd){ /* nothing to do on this one ... check the next one */ prev_client = client; client = client->fcl_next; @@ -269,7 +368,6 @@ check_socket(int num) client = fcrondyn_cl_base = client->fcl_next; else { prev_client->fcl_next = client->fcl_next; - Flush(client->fcl_cmd); Flush(client); client = prev_client->fcl_next; } @@ -289,6 +387,7 @@ check_socket(int num) auth_client(client); else { /* we've just read a command ... */ + client->fcl_idle_since = now; exe_cmd(client); } prev_client = client;