1
0

added debugging and bug on pid suppression corrected

This commit is contained in:
Daniel Tartavel 2020-05-27 00:06:05 +02:00
parent 18d7e878cf
commit 0bb0c7885e

228
main.c
View File

@ -9,16 +9,15 @@
#include <locale.h> #include <locale.h>
#include <libgen.h> #include <libgen.h>
#include <sys/inotify.h> #include <sys/inotify.h>
#include <errno.h>
#define HOSTNAME "localhost" #define HOSTNAME "localhost"
#define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_SIZE (sizeof(struct inotify_event))
#define NONE 0 #define NONE 0
#define INFO 1 #define WARNING 1
#define WARNING 2 #define INFO 2
#define DEBUG 3 #define DEBUG 3
int debug = INFO;
struct connexion struct connexion
{ {
int pid; int pid;
@ -46,7 +45,50 @@ struct notify_config
int wd; int wd;
}; };
struct config cfg = {"","","",""};
int loglevel = DEBUG;
// return date in localized format
char * frtime(const time_t timet)
{
struct tm *date_tm;
static char result[40];
date_tm = localtime(&timet);
strftime(result, 40, "%c", date_tm);
return result;
}
int printlog(char str[], int level, int errnum)
{
FILE * fh = NULL;
time_t now = 0;
char tmp[128];
int retval = EXIT_SUCCESS;
if ( level <= loglevel )
{
if (errnum != 0)
{
sprintf( tmp, "%s: %s %s\n", frtime(now), str, strerror(errnum));
}else
{
sprintf( tmp, "%s: %s\n", frtime(now), str);
}
if ( (fh = fopen(cfg.logfile, "a")) == NULL)
{
perror(cfg.logfile);
retval = EXIT_FAILURE;
}
if ( retval == EXIT_SUCCESS )
{
fprintf(fh, "%s", tmp);
fclose(fh);
}
printf("%s", tmp);
}
return retval;
}
int explode( char * str, char * separator, size_t m, size_t n, char exploded[m][n] ) int explode( char * str, char * separator, size_t m, size_t n, char exploded[m][n] )
{ {
@ -56,7 +98,7 @@ int explode( char * str, char * separator, size_t m, size_t n, char exploded[m][
pch = strtok( str, separator ); pch = strtok( str, separator );
while( pch != NULL ) while( pch != NULL )
{ {
if (debug >= 2) printf("%s\n", pch); printlog( pch, DEBUG, 0);
strcpy( exploded[x++], pch) ; strcpy( exploded[x++], pch) ;
pch = strtok( NULL , separator ); pch = strtok( NULL , separator );
} }
@ -72,6 +114,7 @@ int readconfig( struct config * cfg )
int x; int x;
int retval=0; int retval=0;
char str[1024]; char str[1024];
char strlog[128];
char exploded[2][1024]; char exploded[2][1024];
char * homepath; char * homepath;
char * buff; char * buff;
@ -87,12 +130,13 @@ int readconfig( struct config * cfg )
{ {
if ((fh = fopen( path[x], "r")) == NULL) if ((fh = fopen( path[x], "r")) == NULL)
{ {
if (debug >= 1) perror(path[x]); printlog( path[x], WARNING, errno );
retval = -1; retval = -1;
}else }else
{ {
strcpy( cfg->configfile, path[x]); strcpy( cfg->configfile, path[x]);
if (debug >= 1) printf("Found config file: %s\n", path[x]); sprintf(strlog, "Found config file: %s\n", path[x]);
printlog( strlog, WARNING, 0);
x = 3; x = 3;
retval = 0; retval = 0;
} }
@ -107,24 +151,27 @@ int readconfig( struct config * cfg )
if ( (fh1 = fopen(exploded[1],"r")) != NULL) if ( (fh1 = fopen(exploded[1],"r")) != NULL)
{ {
strcpy( cfg->commande, exploded[1] ); strcpy( cfg->commande, exploded[1] );
if (debug >= 1) printf("Found command: %s\n", cfg->commande); sprintf(strlog, "Found command: %s", cfg->commande);
printlog(strlog, INFO, 0);
fclose(fh1); fclose(fh1);
}else }else
{ {
if (debug >= 1) perror(exploded[1]); printlog( exploded[1], INFO, errno);
} }
}else if( strcmp( exploded[0], "logfile") == 0) }else if( strcmp( exploded[0], "logfile") == 0)
{ {
if ( (fh1 = fopen(exploded[1], "a")) != NULL ) if ( (fh1 = fopen(exploded[1], "a")) != NULL )
{ {
strcpy( cfg->logfile, exploded[1] ); strcpy( cfg->logfile, exploded[1] );
if (debug >= 1) printf("Found logfile: %s\n", cfg->logfile); sprintf( strlog, "Found logfile: %s", cfg->logfile);
printlog(strlog, INFO, 0);
fclose(fh1); fclose(fh1);
} }
}else if( strcmp( exploded[0], "hostname") == 0 ) }else if( strcmp( exploded[0], "hostname") == 0 )
{ {
strcpy( cfg->hostname, exploded[1] ); strcpy( cfg->hostname, exploded[1] );
if (debug >= 1 ) printf("Found hostname: %s\n", cfg->hostname); sprintf(strlog, "Found hostname: %s", cfg->hostname);
printlog(strlog, INFO, 0);
} }
} }
} }
@ -140,7 +187,7 @@ int readconfig( struct config * cfg )
fclose(fh1); fclose(fh1);
}else }else
{ {
if (debug >= 1) perror(logfilepath); printlog( logfilepath, WARNING, errno);
strcpy(cfg->logfile, "/dev/null"); strcpy(cfg->logfile, "/dev/null");
retval += 2; retval += 2;
} }
@ -171,51 +218,48 @@ int readconfig( struct config * cfg )
int isinarray( int pid, int array[], int n ) int isinarray( int pid, int array[], int n )
{ {
int x; int x;
char strlog[128];
for(x=1;x<=n;x++) for(x=1;x<=n;x++)
{ {
if( pid == array[x]) if( pid == array[x])
{ {
if (loglevel >= DEBUG )
{
sprintf(strlog, "pid %i is in array", pid);
printlog(strlog, DEBUG, 0 );
}
return x; return x;
} }
} }
return 0; return 0;
} }
// return date in localized format // initialize config file watching
char* frtime(const time_t timet)
{
struct tm *date_tm;
static char result[40];
date_tm = localtime(&timet);
strftime(result, 40, "%c", date_tm);
return result;
}
int init_config_watch( char config_file[], struct notify_config * ncc ) int init_config_watch( char config_file[], struct notify_config * ncc )
{ {
ncc->fd = inotify_init(); ncc->fd = inotify_init();
if ( ncc->fd < 0 ) if ( ncc->fd < 0 )
{ {
perror( "inotify_init" ); printlog("inotify_init", WARNING, errno );
return -1; return -1;
} }
ncc->wd = inotify_add_watch( ncc->fd, config_file, IN_MODIFY | IN_DELETE ); ncc->wd = inotify_add_watch( ncc->fd, config_file, IN_MODIFY | IN_DELETE );
if (ncc->wd == -1) if (ncc->wd == -1)
{ {
perror(config_file); printlog(config_file, WARNING, errno);
printf("%s\n", config_file);
return -2; return -2;
} }
return 0; return 0;
} }
int notify_config_change(struct notify_config * ncc, char config_file[], struct config * cfg) int notify_config_change(struct notify_config * ncc, char config_file[])
{ {
int length=0; int length=0;
int i=0; int i=0;
int buff_length = (1024 * (EVENT_SIZE + 16)); int buff_length = (1024 * (EVENT_SIZE + 16));
char buff[buff_length]; char buff[buff_length];
char strlog[128];
fd_set rfds; fd_set rfds;
struct timeval tv = {1,0}; struct timeval tv = {1,0};
int retval; int retval;
@ -225,14 +269,14 @@ int notify_config_change(struct notify_config * ncc, char config_file[], struct
retval = select(ncc->fd+1, &rfds, NULL, NULL, &tv); retval = select(ncc->fd+1, &rfds, NULL, NULL, &tv);
if (retval == -1) if (retval == -1)
{ {
if (debug >= 1) perror("select()"); printlog("select()", WARNING, errno);
} }
else if (retval) else if (retval)
{ {
length = read(ncc->fd, buff, buff_length); length = read(ncc->fd, buff, buff_length);
if (length < 0) if (length < 0)
{ {
if (debug >= 1) perror("reading"); printlog("reading", WARNING, errno);
return -1; return -1;
} }
while (i < length) while (i < length)
@ -240,12 +284,14 @@ int notify_config_change(struct notify_config * ncc, char config_file[], struct
struct inotify_event *event = (struct inotify_event *) &buff[i]; struct inotify_event *event = (struct inotify_event *) &buff[i];
if (event->mask & IN_DELETE) if (event->mask & IN_DELETE)
{ {
if (debug >= 2) printf("The file %s was deleted.\n", event->name); sprintf(strlog, "The file %s was deleted.", event->name);
printlog(strlog, INFO, 0);
init_config_watch( config_file, ncc); init_config_watch( config_file, ncc);
} else if (event->mask & IN_MODIFY) } else if (event->mask & IN_MODIFY)
{ {
if (debug >= 2) printf("The file %s was modified.\n", event->name); sprintf(strlog, "The file %s was modified.", event->name);
readconfig(cfg); printlog(strlog, INFO, 0);
readconfig(&cfg);
} }
i += EVENT_SIZE + event->len; i += EVENT_SIZE + event->len;
} }
@ -261,6 +307,7 @@ void getutmp( struct connexion * conn, time_t * time )
int ipv4; int ipv4;
int x; int x;
char str[6]; char str[6];
char strlog[128];
conn->host_ip[0]='\0'; conn->host_ip[0]='\0';
conn->host_ipv6[0]='\0'; conn->host_ipv6[0]='\0';
@ -270,8 +317,10 @@ void getutmp( struct connexion * conn, time_t * time )
if ( utmp->ut_pid == conn->pid ) if ( utmp->ut_pid == conn->pid )
{ {
sprintf(conn->user, "%s", utmp->ut_user); //got user login sprintf(conn->user, "%s", utmp->ut_user); //got user login
printlog(conn->user, DEBUG, 0);
sprintf(conn->hostname, "%s", utmp->ut_host); //got ip of origin sprintf(conn->hostname, "%s", utmp->ut_host); //got ip of origin
if((utmp->ut_addr_v6[1] && utmp->ut_addr_v6[2] && utmp->ut_addr_v6[3]) == 0) printlog(conn->hostname, DEBUG, 0);
if((utmp->ut_addr_v6[1] || utmp->ut_addr_v6[2] || utmp->ut_addr_v6[3]) == 0)
{ {
ipv4 = utmp->ut_addr_v6[0] & 0x00000000000000ff; ipv4 = utmp->ut_addr_v6[0] & 0x00000000000000ff;
sprintf( str, "%d.", ipv4); sprintf( str, "%d.", ipv4);
@ -285,6 +334,7 @@ void getutmp( struct connexion * conn, time_t * time )
ipv4 = (utmp->ut_addr_v6[0] & 0x00000000ff000000) >> 24; ipv4 = (utmp->ut_addr_v6[0] & 0x00000000ff000000) >> 24;
sprintf( str, "%d", ipv4); sprintf( str, "%d", ipv4);
strcat(conn->host_ip, str); strcat(conn->host_ip, str);
printlog(conn->host_ip, DEBUG, 0);
}else }else
{ {
for (x=0;x<4;x++) for (x=0;x<4;x++)
@ -303,8 +353,10 @@ void getutmp( struct connexion * conn, time_t * time )
strcat(conn->host_ipv6, str); strcat(conn->host_ipv6, str);
} }
conn->host_ipv6[strlen(conn->host_ipv6)-1] = '\0'; conn->host_ipv6[strlen(conn->host_ipv6)-1] = '\0';
printlog(conn->host_ipv6, DEBUG, 0);
} }
*time = (time_t) utmp->ut_tv.tv_sec; //got connexion time *time = (time_t) utmp->ut_tv.tv_sec; //got connexion time
sprintf(strlog, "heure de connexion - %s", frtime( *time ) );
break; break;
} }
} }
@ -342,14 +394,16 @@ int getpids(int pid, int exploded[])
char * pch; char * pch;
char path[1024]; char path[1024];
char str[4096]; char str[4096];
char strlog[128];
char separator[] = " "; char separator[] = " ";
int x = 0; int x = 0;
sprintf( path, "/proc/%d/task/%d/children", pid, pid); sprintf( path, "/proc/%d/task/%d/children", pid, pid);
if (debug >= 2) printf("process path: %s\n", path); sprintf(strlog, "process path: %s", path);
printlog(strlog, DEBUG,0);
if ((fh = fopen( path, "r")) == NULL) if ((fh = fopen( path, "r")) == NULL)
{ {
if (debug >= 1) perror(path); printlog(path, WARNING, errno);
return -1; return -1;
} }
if ( fgets( str, 40, fh ) != NULL ) if ( fgets( str, 40, fh ) != NULL )
@ -357,7 +411,7 @@ int getpids(int pid, int exploded[])
pch = strtok( str, separator ); pch = strtok( str, separator );
while( pch != NULL ) while( pch != NULL )
{ {
if (debug >= 2) printf("%s\n", pch); printlog(pch, DEBUG, 0);
exploded[x++] = atoi( pch ); exploded[x++] = atoi( pch );
pch = strtok( NULL , separator ); pch = strtok( NULL , separator );
} }
@ -370,6 +424,7 @@ int getpids(int pid, int exploded[])
} }
} }
// get informations on processus
int getprocinfo( struct connexion * conn ) int getprocinfo( struct connexion * conn )
{ {
FILE *fh1; FILE *fh1;
@ -380,7 +435,7 @@ int getprocinfo( struct connexion * conn )
int r; int r;
int level = 0; int level = 0;
int retval = 0; int retval = 0;
char tab[128]; //char tab[128];
time_t timet=0; time_t timet=0;
//get connexion time //get connexion time
@ -398,7 +453,7 @@ int getprocinfo( struct connexion * conn )
if ( r != -1 ) if ( r != -1 )
{ {
level++; level++;
strcat(tab," "); //strcat(tab," ");
conn->pid = child_pid[0]; conn->pid = child_pid[0];
}else }else
{ {
@ -410,22 +465,24 @@ int getprocinfo( struct connexion * conn )
sprintf( child_path, "/proc/%d/cmdline", conn->pid ); sprintf( child_path, "/proc/%d/cmdline", conn->pid );
if ( (fh1 = fopen( child_path, "r" )) == NULL) if ( (fh1 = fopen( child_path, "r" )) == NULL)
{ {
if (debug >= 1) perror(child_path); printlog(child_path, WARNING, errno);
return 2; return 2;
} }
fgets( str, 1024, fh1); fgets( str, 1024, fh1);
null2space( str ); null2space( str );
sprintf(conn->cmdline, "%s", str); sprintf(conn->cmdline, "%s", str);
fclose(fh1); fclose(fh1);
printlog(conn->cmdline, DEBUG, 0);
if ((strstr(conn->cmdline, "pam") || strstr(conn->cmdline, "net") || strstr(conn->cmdline, "accepted")) != 0) if ((strstr(conn->cmdline, "pam") || strstr(conn->cmdline, "net") || strstr(conn->cmdline, "accepted")) != 0)
{ {
printlog("comdline is pam or net or accepted", DEBUG, 0);
retval = -1; retval = -1;
} }
// get the command name // get the command name
sprintf( child_path, "/proc/%d/comm", conn->pid ); sprintf( child_path, "/proc/%d/comm", conn->pid );
if ( (fh1= fopen(child_path, "r" )) == NULL) if ( (fh1= fopen(child_path, "r" )) == NULL)
{ {
if (debug >= 1) perror(child_path); printlog(child_path, WARNING, errno);
return 3; return 3;
} }
fscanf( fh1, "%s", conn->cmd ); fscanf( fh1, "%s", conn->cmd );
@ -441,12 +498,12 @@ int main()
int n_ssh=10; int n_ssh=10;
int id; int id;
int pid; int pid;
int x=0;
int y=0; int y=0;
int r=0; int r=0;
int i; int i;
int j; int j;
int n; int n;
int n_pid=0;
int start=1; int start=1;
int childrens[n_ssh]; int childrens[n_ssh];
int pids[n_ssh]; int pids[n_ssh];
@ -458,10 +515,11 @@ int main()
char date[60]; char date[60];
time_t now = 0; time_t now = 0;
char * language; char * language;
char strlog[128];
// char * buff; // char * buff;
struct connexion conn; struct connexion conn;
struct connexion connexions[n_ssh]; struct connexion connexions[n_ssh];
struct config cfg = {"","","",""};
struct notify_config ncc; struct notify_config ncc;
//char * ptr; //char * ptr;
@ -480,13 +538,7 @@ int main()
time( &now ); time( &now );
sprintf( date, "%s", frtime(now)); sprintf( date, "%s", frtime(now));
if ( (fh = fopen(cfg.logfile, "a")) == NULL) printlog("Démarrage de sshdetect", INFO, 0);
{
if (debug >= 1) perror(cfg.logfile);
return 7;
}
fprintf(fh, "%s: Démarrage de sshdetect\n", date);
fclose(fh);
sprintf( str, "%s \"%s - %s: Démarrage de sshdetect\"", cfg.commande, cfg.hostname, date ); sprintf( str, "%s \"%s - %s: Démarrage de sshdetect\"", cfg.commande, cfg.hostname, date );
id=fork(); id=fork();
if(id == 0) if(id == 0)
@ -496,30 +548,32 @@ int main()
r = system( str ); r = system( str );
}else }else
{ {
if (debug >= 2) printf("no command defined: no command launched\n"); printlog("no command defined: no command launched", WARNING, 0);
} }
exit(r); exit(r);
}else if( id<0 ) }else if( id<0 )
{ {
if (debug >= 1) printf("erreur de création du fork: %s\n", str); sprintf(strlog, "erreur de création du fork: %s", str);
printlog(strlog, WARNING, 0);
} }
init_config_watch( cfg.configfile, &ncc); init_config_watch( cfg.configfile, &ncc);
while (1) while (1)
{ {
memset(&conn, 0, sizeof(conn));
// get the sshd process ID (PID) // get the sshd process ID (PID)
if ( (fh = fopen("/run/sshd.pid", "r" )) == NULL) if ( (fh = fopen("/run/sshd.pid", "r" )) == NULL)
{ {
if (debug >= 1) perror("/run/sshd.pid"); printlog("/run/sshd.pid", WARNING, errno);
return 1; return 1;
} }
if ( fscanf(fh, "%i", &pid) == 0) if ( fscanf(fh, "%i", &pid) == 0)
{ {
if (debug >= 1) printf("erreur fscanf: /run/sshd.pid\n" ); printlog("erreur fscanf: /run/sshd.pid", WARNING, 0 );
return 10; return 10;
} }
fclose(fh); fclose(fh);
if (debug >= 1) printf("%i", pid); sprintf(strlog, "%i", pid);
printlog(strlog, DEBUG, 0);
//get the list of children //get the list of children
if ( (n=getpids( pid, pids )) != -1) if ( (n=getpids( pid, pids )) != -1)
@ -527,7 +581,9 @@ int main()
for ( y=0; y<n; y++) for ( y=0; y<n; y++)
{ {
pid = pids[y]; pid = pids[y];
r = isinarray(pid, childrens, x); sprintf( strlog, "pid %i", pid);
printlog(strlog, DEBUG, 0);
r = isinarray(pid, childrens, n_pid);
if( r == 0 ) if( r == 0 )
{ {
conn.user[0]='\0'; conn.user[0]='\0';
@ -542,94 +598,82 @@ int main()
{ {
strcpy(ip,conn.host_ipv6); strcpy(ip,conn.host_ipv6);
} }
x++; n_pid++;
childrens[x] = pid; childrens[n_pid] = pid;
flag[x] = 1; flag[n_pid] = 1;
connexions[x] = conn; connexions[n_pid] = conn;
// date of connexion // date of connexion
if (conn.user[0] == '\0') if (conn.user[0] == '\0')
{ {
sprintf( str, "%s \"%s: tunnel ouvert le %s depuis %s pid: %d avec la commande: %s %s\"", cfg.commande, cfg.hostname, conn.date, ip, conn.pid, conn.cmd, conn.cmdline ); sprintf( str, "%s: %s \"%s: tunnel ouvert depuis %s pid: %d avec la commande: %s %s\"", conn.date, cfg.commande, cfg.hostname, ip, conn.pid, conn.cmd, conn.cmdline );
}else }else
{ {
sprintf( str, "%s \"%s: %s s'est connecté le %s depuis %s pid: %d avec la commande: %s %s\"", cfg.commande, cfg.hostname, conn.user, conn.date,ip, conn.pid, conn.cmd, conn.cmdline ); sprintf( str, "%s: %s \"%s: %s s'est connecté depuis %s pid: %d avec la commande: %s %s\"", conn.date, cfg.commande, cfg.hostname, conn.user, ip, conn.pid, conn.cmd, conn.cmdline );
} }
if ( start != 1 ) if ( start != 1 )
{ {
id=fork(); id=fork();
if(id > 0) if(id > 0)
{ {
if ( (fh1 = fopen(cfg.logfile, "a")) == NULL) sprintf(strlog, "%s: Connexion de %s depuis %s commande: %s %s", conn.date, conn.user, ip, conn.cmd, conn.cmdline);
{
if (debug >= 1) perror(cfg.logfile);
return 7;
}
fprintf(fh1, "%s: Connexion de %s depuis %s commande: %s %s\n", conn.date, conn.user, ip, conn.cmd, conn.cmdline);
fclose(fh1);
}else if (id < 0) }else if (id < 0)
{ {
if (debug >= 1) printf("erreur de création du fork: %s\n", str); sprintf(strlog, "erreur de création du fork: %s", str);
printlog(strlog, WARNING, 0);
}else }else
{ {
if (cfg.commande[0] != 0) if (cfg.commande[0] != 0)
{ {
if (debug >= 1) printf("%s\n", str); printlog(str, INFO, 0);
r = system( str ); r = system( str );
}else }else
{ {
if (debug >= 1) printf("no command defined: no command launched\n"); printlog("no command defined: no command launched", WARNING, 0);
} }
exit(r); exit(r);
} }
}else }else
{ {
if ( (fh1 = fopen(cfg.logfile, "a")) == NULL) sprintf(strlog, "%s: %s Connecté depuis %s - %s %s\n", conn.date, conn.user, ip, conn.cmd, conn.cmdline);
{ printlog(strlog, INFO, 0);
if (debug >= 1) perror(cfg.logfile);
return 7;
}
fprintf(fh1, "%s: %s Connecté depuis %s - %s %s\n", conn.date, conn.user, ip, conn.cmd, conn.cmdline);
fclose(fh1);
} }
}else if (rinfo == -1) }else if (rinfo == -1)
{ {
if (debug >= 2) printf("%i => 2 pids : en cours de connexion\n", conn.pid); sprintf(strlog, "%i => 2 pids : en cours de connexion\n", conn.pid);
printlog(strlog, INFO, 0);
} }
}else }else
{ {
flag[r] = 1; flag[r] = 1;
} }
} }
for(i=1;i<=x;i++) }
for(i=1;i<=n_pid;i++)
{ {
if (flag[i] == 0 ) if (flag[i] == 0 )
{ {
time( &now ); time( &now );
sprintf( date, "%s", frtime(now) ); sprintf( date, "%s", frtime(now) );
if (debug >= 2) printf( "Session %d de %s terminée le %s\n", connexions[i].pid, connexions[i].user, date ); sprintf(strlog, "%s: Session %d de %s terminée\n", date, connexions[i].pid, connexions[i].user );
if ( (fh1 = fopen(cfg.logfile, "a")) == NULL) printlog(strlog, INFO, 0);
{ sprintf(strlog, "%s: %s - pid %d - Connexion de %s terminée", connexions[i].date, cfg.hostname, connexions[i].pid, connexions[i].user);
if (debug >= 1) perror(cfg.logfile); printlog(strlog, INFO, 0);
return 7; for( j=i; j<n_pid; j++ )
}
fprintf(fh1, "%s: pid %d -Connexion de %s terminée le %s\n", cfg.hostname, connexions[i].pid, connexions[i].user, connexions[i].date);
for( j=i; j<x; j++ )
{ {
childrens[j] = childrens[j+1]; childrens[j] = childrens[j+1];
flag[j] = flag[j+1]; flag[j] = flag[j+1];
} }
i--; i--;
x--; n_pid--;
}else }else
{ {
flag[i] = 0; flag[i] = 0;
} }
} }
}
waitpid(-1, &status ,WNOHANG); waitpid(-1, &status ,WNOHANG);
// sleep(1); // sleep(1);
notify_config_change(&ncc, cfg.configfile, &cfg); notify_config_change(&ncc, cfg.configfile);
start = 0; start = 0;
} }
return 0; return 0;