* `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 */
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)
/* 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");
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 ) {
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);
}
+
+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 */
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;
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;
}
auth_client(client);
else {
/* we've just read a command ... */
+ client->fcl_idle_since = now;
exe_cmd(client);
}
prev_client = client;