diff --git a/native/Sources/Clients/README.es.txt b/native/Sources/Clients/README.es.txt new file mode 100644 index 0000000..56900d8 --- /dev/null +++ b/native/Sources/Clients/README.es.txt @@ -0,0 +1,9 @@ +OpenGnsys Services for Clients README +======================================= + + +Este directorio contiene el código fuente de los servicios OpenGnsys específicos para clientes. + +- ogAdmClient servicio para cliente ogLive que atiende peticiones de OpenGnsys Server +- ogagent OGAgent: agente modular para sistemas operativos con API REST + diff --git a/native/Sources/Clients/ogAdmClient/Makefile b/native/Sources/Clients/ogAdmClient/Makefile new file mode 100644 index 0000000..d3628c9 --- /dev/null +++ b/native/Sources/Clients/ogAdmClient/Makefile @@ -0,0 +1,31 @@ +# makefile + +# Nombre del proyecto +PROYECTO := ogAdmClient + +# Directorios y librerias +DIRS := +LIBS := -static + +# Opciones de compilacion +OPCS := -m32 -O0 -g -Wall # Depuracion +#OPCS := -m32 -O3 -Wall # Optimizacion + +# Ficheros objetos +OBJS := sources/ogAdmClient.o + +all: $(PROYECTO) + +$(PROYECTO): $(OBJS) + gcc $(OPCS) $(DIRS) $(LIBS) $(OBJS) -o $(PROYECTO) +# strip $(PROYECTO) # Optimizacion + +clean: + rm -f $(PROYECTO) $(OBJS) + +sources/%.o: sources/%.c + gcc $(OPCS) -I ../../Includes -c -o"$@" "$<" + + + + diff --git a/native/Sources/Clients/ogAdmClient/ogAdmClient.cfg b/native/Sources/Clients/ogAdmClient/ogAdmClient.cfg new file mode 100644 index 0000000..b15e740 --- /dev/null +++ b/native/Sources/Clients/ogAdmClient/ogAdmClient.cfg @@ -0,0 +1,5 @@ +ServidorAdm=SERVERIP +PUERTO=2008 +PATHINTERFACE=/opt/opengnsys/interfaceAdm +UrlMenu=OPENGNSYSURL/varios/menubrowser.php +UrlMsg=http://localhost/cgi-bin/httpd-log.sh \ No newline at end of file diff --git a/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.c b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.c new file mode 100644 index 0000000..6f87cc4 --- /dev/null +++ b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.c @@ -0,0 +1,2331 @@ +// ******************************************************************************************************** +// Cliernte: ogAdmClient +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Abril-2010 +// Nombre del fichero: ogAdmClient.c +// Descripción :Este fichero implementa el cliente general del sistema +// ******************************************************************************************************** + +#include "ogAdmClient.h" +#include "ogAdmLib.c" +//________________________________________________________________________________________________________ +// Función: tomaConfiguracion +// +// Descripción: +// Lee el fichero de configuración del servicio +// Parámetros: +// filecfg : Ruta completa al fichero de configuración +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN tomaConfiguracion(char* filecfg) +{ + char modulo[] = "tomaConfiguracion()"; + + if (filecfg == NULL || strlen(filecfg) == 0) { + errorLog(modulo, 1, FALSE); // Fichero de configuración del cliente vacío + return (FALSE); + } + FILE *fcfg; + int lSize; + char * buffer, *lineas[MAXPRM], *dualparametro[2]; + int i, numlin, resul; + + fcfg = fopen(filecfg, "rt"); + if (fcfg == NULL) { + errorLog(modulo, 2, FALSE); // No existe fichero de configuración del cliente + return (FALSE); + } + + fseek(fcfg, 0, SEEK_END); + lSize = ftell(fcfg); // Obtiene tamaño del fichero. + rewind(fcfg); + buffer = (char*) reservaMemoria(lSize+1); // Toma memoria para el buffer de lectura. + if (buffer == NULL) { // No hay memoria suficiente para el buffer + errorLog(modulo, 3, FALSE); + return (FALSE); + } + lSize=fread(buffer, 1, lSize, fcfg); // Lee contenido del fichero + buffer[lSize]=CHARNULL; + fclose(fcfg); + + /* Inicializar variables globales */ + servidoradm[0]=CHARNULL; + puerto[0] = CHARNULL; + pathinterface[0]=CHARNULL; + urlmenu[0]=CHARNULL; + urlmsg[0]=CHARNULL; + + numlin = splitCadena(lineas, buffer, '\n'); + for (i = 0; i < numlin; i++) { + splitCadena(dualparametro, lineas[i], '='); + + resul = strcmp(StrToUpper(dualparametro[0]), "SERVIDORADM"); + if (resul == 0) + strcpy(servidoradm, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "PUERTO"); + if (resul == 0) + strcpy(puerto, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "PATHINTERFACE"); + if (resul == 0) + strcpy(pathinterface, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "URLMENU"); + if (resul == 0) + strcpy(urlmenu, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "URLMSG"); + if (resul == 0) + strcpy(urlmsg, dualparametro[1]); + } + + if (servidoradm[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,4, FALSE); // Falta parámetro SERVIDORADM + return (FALSE); + } + + if (puerto[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,5, FALSE); // Falta parámetro PUERTO + return (FALSE); + } + if (pathinterface[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,56, FALSE); // Falta parámetro PATHINTERFACE + return (FALSE); + } + + if (urlmenu[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,89, FALSE); // Falta parámetro URLMENU + return (FALSE); + } + if (urlmsg[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,90, FALSE); // Falta parámetro URLMSG + return (FALSE); + } + liberaMemoria(buffer); + return (TRUE); +} +//______________________________________________________________________________________________________ +// Función: FinterfaceAdmin +// +// Descripción: +// Esta función es la puerta de comunicación entre el módulo de administración y el motor de clonación. +// La Aplicación de administración utiliza una interface para ejecutar funciones del motor de clonación; +// esta interface llamará a la API del motor con lo que cambiando el comportamiento de esta interface +// podremos hacer llamadas a otras API de clonación y de esta manera probar distintos motores. +// +// Parámetros: +// - script: Nombre del módulo,función o script de la interface +// - parametros: Parámetros que se le pasarán a la interface +// - salida: Recoge la salida que genera la llamada a la interface + +// Devuelve: +// Código de error de la ejecución al módulo , función o script de la interface +// +// Especificaciones: +// El parámetro salida recoge la salida desde un fichero que se genera en la ejecución del script siempre que +// sea distinto de NULL, esto es, si al llamar a la función este parámetro es NULL no se recogerá dicha salida. +// Este fichero tiene una ubicación fija: /tmp/_retinterface +//______________________________________________________________________________________________________ + +int FinterfaceAdmin( char *script,char* parametros,char* salida) +{ + FILE *f; + int lSize,nargs,i,resul; + char msglog[LONSTD],*argumentos[MAXARGS]; + char modulo[] = "FinterfaceAdmin()"; + + + if (ndebug>= DEBUG_MEDIO) { + sprintf(msglog, "%s:%s", tbMensajes[8], script); + infoDebug(msglog); + } + + /* Crea matriz de los argumentos */ + nargs=splitCadena(argumentos,parametros,32); + for(i=nargs;i= DEBUG_ALTO) { + sprintf(msglog, "%s: #%d-%s", tbMensajes[9],i+1,argumentos[i]); + infoDebug(msglog); + } + } + /* Elimina fichero de retorno */ + if(salida!=(char*)NULL){ + f = fopen("/tmp/_retinterface_","w" ); + if (f==NULL){ // Error de eliminación + scriptLog(modulo,10); + resul=8; + scriptLog(modulo,resul); + return(resul); + } + fclose(f); + } + /* Compone linea de comando */ + if(parametros){ + strcat(script," "); + strcat(script,parametros); + } + /* LLamada función interface */ + resul=system(script); + if(resul){ + scriptLog(modulo,10); + scriptLog(modulo,resul); + return(resul); + } + /* Lee fichero de retorno */ + if(salida!=(char*)NULL){ + f = fopen("/tmp/_retinterface_","rb" ); + if (f==NULL){ // Error de apertura + scriptLog(modulo,10); + resul=9; + scriptLog(modulo,resul); + return(resul); + } + else{ + fseek (f ,0,SEEK_END); // Obtiene tamaño del fichero. + lSize = ftell (f); + rewind (f); + if(lSize>LONGITUD_SCRIPTSALIDA){ + scriptLog(modulo,10); + resul=11; + scriptLog(modulo,resul); + return(resul); + } + fread (salida,1,lSize,f); // Lee contenido del fichero + rTrim(salida); + fclose(f); + } + } + /* Muestra información de retorno */ + if(salida!=(char*)NULL){ + if(ndebug>2){ + sprintf(msglog,"Información devuelta %s",salida); + infoDebug(msglog); + } + } + return(resul); +} +//______________________________________________________________________________________________________ +// Función: interfaceAdmin +// +// Descripción: +// Esta función es la puerta de comunicación entre el módulo de administración y el motor de clonación. +// La Aplicación de administración utiliza una interface para ejecutar funciones del motor de clonación; +// esta interface llamará a la API del motor con lo que cambiando el comportamiento de esta interface +// podremos hacer llamadas a otras API de clonación y de esta manera probar distintos motores. +// +// Parámetros: +// - script: Nombre del módulo,función o script de la interface +// - parametros: Parámetros que se le pasarán a la interface +// - salida: Recoge la salida que genera la llamada a la interface + +// Devuelve: +// Código de error de la ejecución al módulo , función o script de la interface +// +// Especificaciones: +// El parámetro salida recoge la salida desde el procedimiento hijo que se genera en la ejecución de éste +// siempre que sea distinto de NULL, esto es, si al llamar a la función este parámetro es NULL no se +// recogerá dicha salida. +//______________________________________________________________________________________________________ + +int interfaceAdmin( char *script,char* parametros,char* salida) +{ + int descr[2]; /* Descriptores de E y S de la turbería */ + int bytesleidos; /* Bytes leidos en el mensaje */ + int estado; + pid_t pid; + char buffer[LONBLK]; // Buffer de lectura de fichero + pipe (descr); + int i,nargs,resul; + int lon; // Longitud de cadena + char msglog[LONSUC]; // Mensaje de registro de sucesos + char *argumentos[MAXARGS]; + char modulo[] = "interfaceAdmin()"; + if (ndebug>= DEBUG_MEDIO) { + sprintf(msglog, "%s:%s", tbMensajes[8], script); + infoDebug(msglog); + } + + /* Crea matriz de los argumentos */ + nargs=splitCadena(argumentos,parametros,32); + for(i=nargs;i= DEBUG_ALTO) { + // Truncar la cadena si es mayor que el tamaño de la línea de log. + sprintf(msglog, "%s: #%d-", tbMensajes[9], i+1); + lon = strlen (msglog); + if (lon + strlen (argumentos[i]) < LONSUC) { + strcat (msglog, argumentos[i]); + } + else + { + strncat (msglog, argumentos[i], LONSUC - lon - 4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + } + + if((pid=fork())==0) + { + //_______________________________________________________________ + + /* Proceso hijo que ejecuta la función de interface */ + + close (descr[LEER]); + dup2 (descr[ESCRIBIR], 1); + close (descr[ESCRIBIR]); + resul=execv(script,argumentos); + //resul=execlp (script, script, argumentos[0],argumentos[1],NULL); + exit(resul); + + /* Fin de proceso hijo */ + //_______________________________________________________________ + } + else + { + //_______________________________________________________________ + + /* Proceso padre que espera la ejecución del hijo */ + + if (pid ==-1){ // Error en la creación del proceso hijo + scriptLog(modulo,10); + resul=13; + scriptLog(modulo,resul); + return(resul); + } + close (descr[ESCRIBIR]); + bytesleidos = read (descr[LEER], buffer, LONBLK-1); + while(bytesleidos>0){ + if(salida!=(char*)NULL){ // Si se solicita retorno de información... + buffer[bytesleidos]='\0'; + // Error si se supera el tamaño máximo de cadena de salida. + if(strlen(buffer)+strlen(salida)>LONGITUD_SCRIPTSALIDA){ + scriptLog(modulo,10); + resul=11; + scriptLog(modulo,resul); + return(resul); + } + rTrim(buffer); + strcat(salida,buffer); + } + bytesleidos = read (descr[LEER], buffer, LONBLK-1); + } + close (descr[LEER]); + //kill(pid,SIGQUIT); + waitpid(pid,&estado,0); + resul=WEXITSTATUS(estado); + if(resul){ + scriptLog(modulo,10); + scriptLog(modulo,resul); + return(resul); + } + /* Fin de proceso padre */ + //_______________________________________________________________ + } + + /* Muestra información de retorno */ + if(salida!=(char*)NULL){ + if(ndebug>2){ + // Truncar la cadena si es mayor que el tamaño de la línea de log. + strcpy(msglog,"Informacion devuelta "); + lon = strlen (msglog); + if (lon + strlen (salida) < LONSUC) { + strcat (msglog, salida); + } + else + { + strncat (msglog, salida, LONSUC-lon-4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + } + return(resul); +} +//______________________________________________________________________________________________________ +// Función: scriptLog +// +// Descripción: +// Registra los sucesos de errores de scripts en el fichero de log +// Parametros: +// - modulo: Módulo donde se produjo el error +// - coderr : Código del mensaje de error del script +//______________________________________________________________________________________________________ +void scriptLog(const char *modulo,int coderr) +{ + char msglog[LONSUC]; + + if(coderr>>>>>>>>>>>>>>>>>>>>>>>>> + char msglog[LONSTD]; + char modulo[] = "cuestionCache()"; + + sprintf(interface,"%s/%s",pathinterface,"procesaCache"); + sprintf(parametros,"%s %s","procesaCache",tam); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s",tbErrores[88]); + errorInfo(modulo,msglog); + return(FALSE); + } + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: cargaPaginaWeb +// +// Descripción: +// Muestra una pégina web usando el browser +// Parámetros: +// urp: Dirección url de la página +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +int cargaPaginaWeb(char *url) +{ + pid_t pidbrowser; // Identificador del proceso que se crea para mostrar una página web con el browser + int resul=0; + char* argumentos[4]; + char modulo[] = "cargaPaginaWeb()"; + + // Destruye los procesos del Browser y lanza uno nuevo. + system("pkill -9 browser"); + + sprintf(interface,"/opt/opengnsys/bin/browser"); + sprintf(parametros,"browser -qws %s",url); + + splitCadena(argumentos,parametros,' '); // Crea matriz de los argumentos del scripts + argumentos[3]=NULL; + if((pidbrowser=fork())==0){ + /* Proceso hijo que ejecuta el script */ + resul=execv(interface,argumentos); + exit(resul); + } + else { + if (pidbrowser ==-1){ + scriptLog(modulo,10); + resul=13; + scriptLog(modulo,resul); + return(resul); + } + } + return(resul); +} +//________________________________________________________________________________________________________ +// Función: muestraMenu +// +// Descripción: +// Muestra el menu inicial del cliente +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +void muestraMenu() +{ + cargaPaginaWeb(urlmenu); +} +//______________________________________________________________________________________________________ +// Función: muestraMensaje +// +// Descripción: +// Muestra un mensaje en pantalla +// Parámetros: +// - idx: Indice del mensaje +// - msg: Descripción Mensaje +// ________________________________________________________________________________________________________ +void muestraMensaje(int idx,char*msg) +{ + char *msgpan,url[250]; + + if(msg){ + msgpan=URLEncode(msg); + sprintf(url,"%s?msg=%s",urlmsg,msgpan); // Url de la página de mensajes + liberaMemoria(msgpan); + } + else + sprintf(url,"%s?idx=%d",urlmsg,idx); // Url de la página de mensajes + cargaPaginaWeb(url); +} +//______________________________________________________________________________________________________ +// Función: InclusionCliente +// Descripción: +// Abre una sesión en el servidor de administración y registra al cliente en el sistema +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN inclusionCliente(TRAMA* ptrTrama) +{ + int lon; // Longitud de cadena + char msglog[LONSUC]; // Mensaje de registro de sucesos + char *cfg; // Datos de configuración + SOCKET socket_c; + char modulo[] = "inclusionCliente()"; + + cfg=LeeConfiguracion(); + + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + errorLog(modulo,37,FALSE); + return(FALSE); + } + if (ndebug>= DEBUG_ALTO) { + // Truncar la cadena si es mayor que el tamaño de la línea de log. + sprintf(msglog, "%s", tbMensajes[14]); + lon = strlen (msglog); + if (lon + strlen (cfg) < LONSUC) { + strcat (msglog, cfg); + } + else + { + strncat (msglog, cfg, LONSUC - lon - 4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=InclusionCliente\r"); // Nombre de la función a ejecutar en el servidor + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + liberaMemoria(cfg); + + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,37,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RESPUESTA_InclusionCliente +// +// Descripción: +// Respuesta del servidor de administración a la petición de inicio +// enviando los datos identificativos del cliente y otras configuraciones +// Parámetros: +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RESPUESTA_InclusionCliente(TRAMA* ptrTrama) +{ + char* res; + char modulo[] = "RESPUESTA_InclusionCliente()"; + + res=copiaParametro("res",ptrTrama); // Resultado del proceso de inclusión + if(atoi(res)==0){ // Error en el proceso de inclusión + liberaMemoria(res); + errorLog(modulo,41,FALSE); + return (FALSE); + } + liberaMemoria(res); + + idordenador=copiaParametro("ido",ptrTrama); // Identificador del ordenador + nombreordenador=copiaParametro("npc",ptrTrama); // Nombre del ordenador + cache=copiaParametro("che",ptrTrama); // Tamaño de la caché reservada al cliente + idproautoexec=copiaParametro("exe",ptrTrama); // Procedimento de inicio (Autoexec) + idcentro=copiaParametro("idc",ptrTrama); // Identificador de la Unidad Organizativa + idaula=copiaParametro("ida",ptrTrama); // Identificador del aula + + if(idordenador==NULL || nombreordenador==NULL){ + errorLog(modulo,40,FALSE); + return (FALSE); + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// +// Función: LeeConfiguracion +// Descripción: +// Abre una sesión en el servidor de administración y registra al cliente en el sistema +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ + +char* LeeConfiguracion() +{ + char* parametroscfg; + char modulo[] = "LeeConfiguracion()"; + int herrorcfg; + + // Reservar memoria para los datos de cofiguración. + parametroscfg=(char*)reservaMemoria(LONGITUD_SCRIPTSALIDA); + if(!parametroscfg){ + errorLog(modulo,3,FALSE); + return(NULL); + } + // Ejecutar script y obtener datos. + sprintf(interface,"%s/%s",pathinterface,"getConfiguration"); + herrorcfg=interfaceAdmin(interface,NULL,parametroscfg); + + if(herrorcfg){ // No se puede recuperar la configuración del cliente + liberaMemoria(parametroscfg); + errorLog(modulo,36,FALSE); + return(NULL); + } + return(parametroscfg); +} +//________________________________________________________________________________________________________ +// Función: autoexecCliente +// +// Descripción: +// Solicita procedimiento de autoexec para el cliebnte +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN autoexecCliente(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char modulo[] = "autoexecCliente()"; + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=AutoexecCliente\rexe=%s\r",idproautoexec); + + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + + return(TRUE); +} +//________________________________________________________________________________________________________ +// Función: autoexecCliente +// +// Descripción: +// Ejecuta un script de autoexec personalizado en todos los inicios para el cliente +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN RESPUESTA_AutoexecCliente(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char *res,*nfl; + char modulo[] = "RESPUESTA_AutoexecCliente()"; + + res=copiaParametro("res",ptrTrama); + if(atoi(res)==0){ // Error en el proceso de autoexec + liberaMemoria(res); + return (FALSE); + } + liberaMemoria(res); + + nfl=copiaParametro("nfl",ptrTrama); + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=enviaArchivo\rnfl=%s\r",nfl); + liberaMemoria(nfl); + + /* Envía petición */ + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Nombre del archivo destino (local)*/ + char fileautoexec[LONPRM]; + sprintf(fileautoexec,"/tmp/_autoexec_%s",IPlocal); + + /* Recibe archivo */ + if(!recArchivo(&socket_c,fileautoexec)){ + errorLog(modulo,58, FALSE); + close(socket_c); + return(FALSE); + } + + close(socket_c); + + /* Ejecuta archivo */ + ejecutaArchivo(fileautoexec,ptrTrama); + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: comandosPendientes +// +// Descripción: +// Búsqueda de acciones pendientes en el servidor de administración +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN comandosPendientes(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char modulo[] = "comandosPendientes()"; + + CMDPTES=TRUE; + initParametros(ptrTrama,0); + + while(CMDPTES){ + sprintf(ptrTrama->parametros,"nfn=ComandosPendientes\r"); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: NoComandosPtes +// +// Descripción: +// Conmuta el switch de los comandos pendientes y lo pone a false +// Parámetros: +// - ptrTrama: contenido del mensaje +// Devuelve: +// TRUE siempre +// Especificaciones: +// Cuando se ejecuta esta función se sale del bucle que recupera los comandos pendientes en el +// servidor y el cliente pasa a a estar disponible para recibir comandos desde el éste. +//______________________________________________________________________________________________________ +BOOLEAN NoComandosPtes(TRAMA* ptrTrama) +{ + CMDPTES=FALSE; // Corta el bucle de comandos pendientes + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: ProcesaComandos +// +// Descripción: +// Espera comando desde el Servidor de Administración para ejecutarlos +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +void procesaComandos(TRAMA* ptrTrama) +{ + int lon; + SOCKET socket_c; + char modulo[] = "procesaComandos()"; + + initParametros(ptrTrama,0); + while(TRUE){ + lon=sprintf(ptrTrama->parametros,"nfn=DisponibilidadComandos\r"); + lon+=sprintf(ptrTrama->parametros+lon,"tpc=%s\r",CLIENTE_OPENGNSYS); // Activar disponibilidad + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_INFORMACION)){ + errorLog(modulo,43,FALSE); + return; + } + infoLog(19); // Disponibilidad de cliente activada + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,46,FALSE); + return; + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return; + } + if(!comandosPendientes(ptrTrama)){ + errorLog(modulo,42,FALSE); + } + } +} +//______________________________________________________________________________________________________ +// Función: Actualizar +// +// Descripción: +// Actualiza los datos de un ordenador como si volviera a solicitar la entrada +// en el sistema al servidor de administración +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Actualizar(TRAMA* ptrTrama) +{ + char msglog[LONSTD]; // Mensaje de log + char *cfg; // Cadena de datos de configuración + int lon; // Longitud de cadena + char modulo[] = "Actualizar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + muestraMensaje(1,NULL); + if(!comandosPendientes(ptrTrama)){ + errorLog(modulo,84,FALSE); + return(FALSE); + } + + cfg=LeeConfiguracion(); + herror=0; + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + herror=3; + } + // Envia Configuracion al servidor + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Configurar"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,0); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: Purgar +// +// Descripción: +// Detiene la ejecución del browser +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +int Purgar(TRAMA* ptrTrama) +{ + + exit(EXIT_SUCCESS); +} +//______________________________________________________________________________________________________ +// Función: Sondeo +// +// Descripción: +// Envía al servidor una confirmación de que está dentro del sistema +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Sondeo(TRAMA* ptrTrama) +{ + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: ConsolaRemota +// +// Descripción: +// Ejecuta un comando de la Shell y envia el eco al servidor (Consola remota) +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN ConsolaRemota(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char *nfn,*scp,*aux,ecosrc[LONPRM],ecodst[LONPRM],msglog[LONSTD];; + char modulo[] = "ConsolaRemota()"; + + /* Nombre del archivo de script */ + char filescript[LONPRM]; + sprintf(filescript,"/tmp/_script_%s",IPlocal); + + aux=copiaParametro("scp",ptrTrama); + scp=URLDecode(aux); + escribeArchivo(filescript,scp); + liberaMemoria(aux); + liberaMemoria(scp); + + nfn=copiaParametro("nfn",ptrTrama); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(ecosrc,"/tmp/_econsola_%s",IPlocal); + sprintf(parametros,"%s %s %s",nfn,filescript,ecosrc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(ecodst,"/tmp/_Seconsola_%s",IPlocal); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",ecodst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + recibeFlag(&socket_c,ptrTrama); + /* Envía archivo */ + if(!sendArchivo(&socket_c,ecosrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + } + liberaMemoria(nfn); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Comando +// +// Descripción: +// COmando personalizado enviado desde el servidor +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Comando(TRAMA* ptrTrama) +{ + char *ids,*nfn,msglog[LONSTD]; + char modulo[] = "Comando()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + /* Envia respuesta de ejecucución del comando */ + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=RESPUESTA_%s\r",nfn); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Arrancar +// +// Descripción: +// Responde a un comando de encendido por la red +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Arrancar(TRAMA* ptrTrama) +{ + int lon; + char *ids,msglog[LONSTD]; + char modulo[] = "Arrancar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + ids=copiaParametro("ids",ptrTrama); + + /* Envia respuesta de ejecucución del script */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Arrancar"); + lon+=sprintf(ptrTrama->parametros+lon,"tpc=%s\r",CLIENTE_OPENGNSYS); + respuestaEjecucionComando(ptrTrama,0,ids); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Apagar +// +// Descripción: +// Apaga el cliente +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Apagar(TRAMA* ptrTrama) +{ + char *ids,*nfn,msglog[LONSTD]; + char modulo[] = "Apagar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Apagar"); + respuestaEjecucionComando(ptrTrama,0,ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + liberaMemoria(ids); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Reiniciar +// +// Descripción: +// Apaga el cliente +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Reiniciar(TRAMA* ptrTrama) +{ + char *nfn,*ids,msglog[LONSTD]; + char modulo[] = "Reiniciar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Reiniciar"); + respuestaEjecucionComando(ptrTrama,0,ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + liberaMemoria(ids); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: IniciarSesion +// +// Descripción: +// Inicia sesión en el Sistema Operativo de una de las particiones +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN IniciarSesion(TRAMA* ptrTrama) +{ + char *nfn,*ids,*disk,*par,msglog[LONSTD]; + char modulo[] = "IniciarSesion()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + disk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_IniciarSesion"); + respuestaEjecucionComando(ptrTrama,0,ids); + liberaMemoria(ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s",nfn,disk,par); + liberaMemoria(par); + + herror=interfaceAdmin(interface,parametros,NULL); + + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearImagen +// +// Descripción: +// Crea una imagen de una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearImagen(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*cpt,*idi,*ipr,*nci,*ids,msglog[LONSTD]; + char modulo[] = "CrearImagen()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + cpt=copiaParametro("cpt",ptrTrama); // Código de la partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(7,NULL); + + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(2,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s",nfn,dsk,par,nci,ipr); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(10,NULL); + } + else + muestraMensaje(9,NULL); + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearImagen"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición de donde se creó + lon+=sprintf(ptrTrama->parametros+lon,"cpt=%s\r",cpt); // Tipo o código de partición + lon+=sprintf(ptrTrama->parametros+lon,"ipr=%s\r",ipr); // Ip del repositorio donde se alojó + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(cpt); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(ipr); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearImagenBasica +// +// Descripción: +// Crea una imagen básica a travers dela sincronización +// Parámetros: +// ptrTrama: contenido del mensaje +// +// FDevuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearImagenBasica(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*cpt,*idi,*nci,*rti,*ipr,*msy,*whl,*eli,*cmp,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "CrearImagenBasica()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + cpt=copiaParametro("cpt",ptrTrama); // Tipo de partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + + msy=copiaParametro("msy",ptrTrama); // Método de sincronización + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + muestraMensaje(7,NULL); // Creando Inventario Software + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(30,NULL);// Creando Imagen Básica, por favor espere... + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s%s%s %s%s%s%s %s %s",nfn,dsk,par,nci,ipr,whl,eli,cmp,bpi,cpc,bpc,nba,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(29,NULL);// Ha habido algún error en el proceso de creación de imagen básica + } + else + muestraMensaje(28,NULL);// El proceso de creación de imagen básica ha terminado correctamente + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + ids=copiaParametro("ids",ptrTrama); // Identificador de la sesión + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearImagenBasica"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición de donde se creó + lon+=sprintf(ptrTrama->parametros+lon,"cpt=%s\r",cpt); // Tipo o código de partición + lon+=sprintf(ptrTrama->parametros+lon,"ipr=%s\r",ipr); // Ip del repositorio donde se alojó + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(cpt); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ipr); + + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearSoftIncremental +// +// Descripción: +// Crea una software incremental comparando una partición con una imagen básica +// Parámetros: +// ptrTrama: contenido del mensaje +// +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearSoftIncremental(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*idf,*ipr,*nci,*rti,*ncf,*msy,*whl,*eli,*cmp,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "CrearSoftIncremental()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + idf=copiaParametro("idf",ptrTrama); // Identificador de la imagen diferencial + ncf=copiaParametro("ncf",ptrTrama); // Nombre canónico de la imagen diferencial + + msy=copiaParametro("msy",ptrTrama); // Método de sincronización + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + muestraMensaje(7,NULL); // Creando Inventario Software + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(25,NULL);// Creando Imagen Incremental, por favor espere... + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s%s%s %s%s%s%s %s %s",nfn,dsk,par,nci,ipr,ncf,whl,eli,cmp,bpi,cpc,bpc,nba,msy,rti); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(27,NULL);// Ha habido algún error en el proceso de creación de imagen básica + } + else + muestraMensaje(26,NULL);// El proceso de creación de imagen incremental ha terminado correctamente + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + ids=copiaParametro("ids",ptrTrama); // Identificador de la sesión + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearSoftIncremental"); + lon+=sprintf(ptrTrama->parametros+lon,"idf=%s\r",idf); // Identificador de la imagen incremental + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ipr); + liberaMemoria(idf); + liberaMemoria(ncf); + liberaMemoria(msy); + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarImagen +// +// Descripción: +// Restaura una imagen en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En bpccaso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarImagen(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*ifs,*cfg,*nci,*ids,*ptc,msglog[LONSTD]; + char modulo[] = "RestaurarImagen()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + nci=copiaParametro("nci",ptrTrama); + ifs=copiaParametro("ifs",ptrTrama); + ptc=copiaParametro("ptc",ptrTrama); + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(3,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s",nfn,dsk,par,nci,ipr,ptc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(12,NULL); + } + else + muestraMensaje(11,NULL); + + /* Obtener nueva configuración */ + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarImagen"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de discos + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(ipr); + liberaMemoria(ifs); + liberaMemoria(cfg); + liberaMemoria(ptc); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarImagenBasica +// +// Descripción: +// Restaura una imagen básica en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarImagenBasica(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*met,*nci,*rti,*ifs,*cfg,*msy,*whl,*eli,*cmp,*tpt,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "RestaurarImagenBasica()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + met=copiaParametro("met",ptrTrama); // Método de clonación 0= desde caché 1= desde repositorio + nci=copiaParametro("nci",ptrTrama); + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ifs=copiaParametro("ifs",ptrTrama); + + tpt=copiaParametro("tpt",ptrTrama); // Tipo de trasnmisión unicast o multicast + msy=copiaParametro("msy",ptrTrama); // Metodo de sincronizacion + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(31,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s%s%s %s%s%s%s %s %s %s",nfn,dsk,par,nci,ipr,tpt,whl,eli,cmp,bpi,cpc,bpc,nba,met,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(33,NULL); + } + else + muestraMensaje(32,NULL); + + /* Obtener nueva configuración */ + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarImagenBasica"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de discos + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ifs); + liberaMemoria(cfg); + liberaMemoria(ipr); + liberaMemoria(met); + + liberaMemoria(tpt); + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarSoftIncremental +// +// Descripción: +// Restaura software incremental en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarSoftIncremental(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*met,*ifs,*nci,*rti,*idf,*ncf,*msy,*whl,*eli,*cmp,*tpt,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "RestaurarSoftIncremental()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + idf=copiaParametro("idf",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + met=copiaParametro("met",ptrTrama); // Método de clonación 0= desde caché 1= desde repositorio + ifs=copiaParametro("ifs",ptrTrama); + nci=copiaParametro("nci",ptrTrama); + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ncf=copiaParametro("ncf",ptrTrama); + + tpt=copiaParametro("tpt",ptrTrama); // Tipo de trasnmisión unicast o multicast + msy=copiaParametro("msy",ptrTrama); // Metodo de sincronizacion + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(31,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s %s%s%s %s%s%s%s %s %s %s",nfn,dsk,par,nci,ipr,ncf,tpt,whl,eli,cmp,bpi,cpc,bpc,nba,met,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(35,NULL); + } + else + muestraMensaje(34,NULL); + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarSoftIncremental"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idf); // Identificador de la imagen incremental (Forzada a idi) + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(idf); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ncf); + liberaMemoria(ifs); + liberaMemoria(ipr); + liberaMemoria(met); + + liberaMemoria(tpt); + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: Configurar +// +// Descripción: +// Configura la tabla de particiones y formatea +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Configurar(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*cfg,*ids,msglog[LONSTD]; + char modulo[] = "Configurar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); + cfg=copiaParametro("cfg",ptrTrama); + /* Sustituir caracteres */ + sustituir(cfg,'\n','$'); + sustituir(cfg,'\t','#'); + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(4,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s",nfn,dsk,cfg); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(13,NULL); + } + else + muestraMensaje(14,NULL); + + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + return(FALSE); + } + + /* Envia respuesta de ejecución del comando*/ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Configurar"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(dsk); + liberaMemoria(cfg); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: InventarioHardware +// +// Descripción: +// Envia al servidor el nombre del archivo de inventario de su hardware para posteriormente +// esperar que éste lo solicite y enviarlo por la red. +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventarioHardware(TRAMA* ptrTrama) +{ + int lon; + SOCKET socket_c; + char *nfn,*ids,msglog[LONSTD],hrdsrc[LONPRM],hrddst[LONPRM]; + char modulo[] = "InventarioHardware()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(6,NULL); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(hrdsrc,"/tmp/Chrd-%s",IPlocal); // Nombre que tendra el archivo de inventario + sprintf(parametros,"%s %s",nfn,hrdsrc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(18,NULL); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(hrddst,"/tmp/Shrd-%s",IPlocal); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",hrddst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + liberaMemoria(nfn); + liberaMemoria(ids); + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + recibeFlag(&socket_c,ptrTrama); + /* Envía archivo */ + if(!sendArchivo(&socket_c,hrdsrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + muestraMensaje(17,NULL); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_InventarioHardware"); + lon+=sprintf(ptrTrama->parametros+lon,"hrd=%s\r",hrddst); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: InventarioSoftware +// +// Descripción: +// Crea el inventario software de un sistema operativo instalado en una partición. +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventarioSoftware(TRAMA* ptrTrama) +{ + char *nfn,*ids,msglog[LONSTD]; + char modulo[] = "InventarioSoftware()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(7,NULL); + InventariandoSoftware(ptrTrama,TRUE,nfn); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + muestraMenu(); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// +// Función: InventariandoSoftware +// +// Descripción: +// Envia al servidor el nombre del archivo de inventario de su software para posteriormente +// esperar que éste lo solicite y enviarlo por la red. +// Parámetros: +// ptrTrama: contenido del mensaje +// sw: switch que indica si la función es llamada por el comando InventarioSoftware(true) o CrearImagen(false) +// nfn: Nombre de la función del Interface que implementa el comando +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventariandoSoftware(TRAMA* ptrTrama,BOOLEAN sw,char *nfn) +{ + int lon; + SOCKET socket_c; + char *dsk,*par,msglog[LONSTD],sftsrc[LONPRM],sftdst[LONPRM]; + char modulo[] = "InventariandoSoftware()"; + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(sftsrc,"/tmp/CSft-%s-%s",IPlocal,par); // Nombre que tendra el archivo de inventario + sprintf(parametros,"%s %s %s %s",nfn,dsk,par,sftsrc); + + herror=interfaceAdmin(interface,parametros,NULL); + herror=0; + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(20,NULL); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(sftdst,"/tmp/Ssft-%s-%s",IPlocal,par); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",sftdst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + errorLog(modulo,42,FALSE); + liberaMemoria(dsk); + liberaMemoria(par); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + if(!recibeFlag(&socket_c,ptrTrama)){ + errorLog(modulo,17,FALSE); + } + /* Envía archivo */ + if(!sendArchivo(&socket_c,sftsrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + muestraMensaje(19,NULL); + } + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_InventarioSoftware"); + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); + lon+=sprintf(ptrTrama->parametros+lon,"sft=%s\r",sftdst); + if(!sw) + respuestaEjecucionComando(ptrTrama,herror,"0"); + + liberaMemoria(dsk); + liberaMemoria(par); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: EjecutarScript +// +// Descripción: +// Ejecuta código de script +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN EjecutarScript(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*aux,*ids,*scp,*cfg,msglog[LONSTD]; + char modulo[] = "EjecutarScript()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + aux=copiaParametro("scp",ptrTrama); + scp=URLDecode(aux); + + + muestraMensaje(8,NULL); + /* Nombre del archivo de script */ + char filescript[LONPRM]; + sprintf(filescript,"/tmp/_script_%s",IPlocal); + escribeArchivo(filescript,scp); + nfn=copiaParametro("nfn",ptrTrama); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s",nfn,filescript); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(21,NULL); + } + else + muestraMensaje(22,NULL); + + // Toma configuración de particiones + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + herror=36; + } + + ids=copiaParametro("ids",ptrTrama); + + //herror=ejecutarCodigoBash(scp); + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_EjecutarScript"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(ids); + liberaMemoria(aux); + liberaMemoria(scp); + liberaMemoria(cfg); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: respuestaEjecucionComando +// +// Descripción: +// Envia una respuesta a una ejecucion de comando al servidor de Administración +// Parámetros: +// - ptrTrama: contenido del mensaje +// - res: Resultado de la ejecución (Código de error devuelto por el script ejecutado) +// - ids: Identificador de la sesion (En caso de no haber seguimiento es NULO) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN respuestaEjecucionComando(TRAMA* ptrTrama,int res,char *ids) +{ + int lon; + SOCKET socket_c; + char modulo[] = "respuestaEjecucionComando()"; + + lon=strlen(ptrTrama->parametros); + if(ids){ // Existe seguimiento + lon+=sprintf(ptrTrama->parametros+lon,"ids=%s\r",ids); // Añade identificador de la sesión + } + if (res==0){ // Resultado satisfactorio + lon+=sprintf(ptrTrama->parametros+lon,"res=%s\r","1"); + lon+=sprintf(ptrTrama->parametros+lon,"der=%s\r",""); + } + else{ // Algún error + lon+=sprintf(ptrTrama->parametros+lon,"res=%s\r","2"); + if(res>MAXERRORSCRIPT) + lon+=sprintf(ptrTrama->parametros+lon,"der=%s (Error de script:%d)\r",tbErroresScripts[0],res);// Descripción del error + else + lon+=sprintf(ptrTrama->parametros+lon,"der=%s\r",tbErroresScripts[res]);// Descripción del error + } + if(!(enviaMensajeServidor(&socket_c,ptrTrama,MSG_NOTIFICACION))){ + errorLog(modulo,44,FALSE); + return(FALSE); + } + + close(socket_c); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: gestionaTrama +// +// Descripción: +// Procesa las tramas recibidas. +// Parametros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN gestionaTrama(TRAMA *ptrTrama) +{ + int i, res; + char *nfn; + char modulo[] = "gestionaTrama()"; + + INTROaFINCAD(ptrTrama); + nfn = copiaParametro("nfn", ptrTrama); // Toma nombre de función + for (i = 0; i < MAXIMAS_FUNCIONES; i++) { // Recorre funciones que procesan las tramas + res = strcmp(tbfuncionesClient[i].nf, nfn); + if (res == 0) { // Encontrada la función que procesa el mensaje + liberaMemoria(nfn); + return(tbfuncionesClient[i].fptr(ptrTrama)); // Invoca la función + } + } + + liberaMemoria(nfn); + + /* Sólo puede ser un comando personalizado + if (ptrTrama->tipo==MSG_COMANDO) + return(Comando(ptrTrama)); + */ + errorLog(modulo, 18, FALSE); + return (FALSE); +} +//________________________________________________________________________________________________________ +// Función: ejecutaArchivo +// +// Descripción: +// Ejecuta los comando contenido en un archivo (cada comando y sus parametros separados por un +// salto de linea. +// Parámetros: +// filecmd: Nombre del archivo de comandos +// ptrTrama: Puntero a una estructura TRAMA usada en las comunicaciones por red (No debe ser NULL) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN ejecutaArchivo(char* filecmd,TRAMA *ptrTrama) +{ + char* buffer,*lineas[MAXIMAS_LINEAS]; + int i,numlin; + char modulo[] = "ejecutaArchivo()"; + + buffer=leeArchivo(filecmd); + if(buffer){ + numlin = splitCadena(lineas, buffer, '@'); + initParametros(ptrTrama,0); + for (i = 0; i < numlin; i++) { + if(strlen(lineas[i])>0){ + strcpy(ptrTrama->parametros,lineas[i]); + //strcat(ptrTrama->parametros,"\rMCDJ@"); // Fin de trama + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + //return(FALSE); + } + } + } + } + liberaMemoria(buffer); + return(TRUE); +} + +BOOLEAN EjecutaComandosPendientes(TRAMA* ptrTrama) +{ + return(TRUE); +} + +//______________________________________________________________________________________________________ +// Función: enviaMensajeServidor +// +// Descripción: +// Envia un mensaje al servidor de Administración +// Parámetros: +// - socket_c: (Salida) Socket utilizado para el envío +// - ptrTrama: contenido del mensaje +// - tipo: Tipo de mensaje +// C=Comando, N=Respuesta a un comando, P=Peticion,R=Respuesta a una petición, I=Informacion +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN enviaMensajeServidor(SOCKET *socket_c,TRAMA *ptrTrama,char tipo) +{ + int lon; + char modulo[] = "enviaMensajeServidor()"; + + *socket_c=abreConexion(); + if(*socket_c==INVALID_SOCKET){ + errorLog(modulo,38,FALSE); // Error de conexión con el servidor + return(FALSE); + } + ptrTrama->arroba='@'; // Cabecera de la trama + strncpy(ptrTrama->identificador,"JMMLCAMDJ_MCDJ",14); // identificador de la trama + ptrTrama->tipo=tipo; // Tipo de mensaje + lon=strlen(ptrTrama->parametros); // Compone la trama + lon+=sprintf(ptrTrama->parametros+lon,"iph=%s\r",IPlocal); // Ip del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"ido=%s\r",idordenador); // Identificador del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"npc=%s\r",nombreordenador); // Nombre del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"idc=%s\r",idcentro); // Identificador del centro + lon+=sprintf(ptrTrama->parametros+lon,"ida=%s\r",idaula); // Identificador del aula + + if (!mandaTrama(socket_c,ptrTrama)) { + errorLog(modulo,26,FALSE); + return (FALSE); + } + return(TRUE); +} +// ******************************************************************************************************** +// PROGRAMA PRINCIPAL (CLIENTE) +// ******************************************************************************************************** +int main(int argc, char *argv[]) +{ + TRAMA *ptrTrama; + char modulo[] = "main()"; + + ptrTrama=(TRAMA *)reservaMemoria(sizeof(TRAMA)); + if (ptrTrama == NULL) { // No hay memoria suficiente para el bufer de las tramas + errorLog(modulo, 3, FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Validación de parámetros de ejecución y fichero de configuración + ---------------------------------------------------------------------------------------------------------*/ + if (!validacionParametros(argc, argv,3)) // Valida parámetros de ejecución + exit(EXIT_FAILURE); + + if (!tomaConfiguracion(szPathFileCfg)) // Toma parametros de configuración + exit(EXIT_FAILURE); + /*-------------------------------------------------------------------------------------------------------- + Carga catálogo de funciones que procesan las tramas + ---------------------------------------------------------------------------------------------------------*/ + int cf = 0; + + strcpy(tbfuncionesClient[cf].nf, "RESPUESTA_AutoexecCliente"); + tbfuncionesClient[cf++].fptr = &RESPUESTA_AutoexecCliente; + + strcpy(tbfuncionesClient[cf].nf, "RESPUESTA_InclusionCliente"); + tbfuncionesClient[cf++].fptr = &RESPUESTA_InclusionCliente; + + strcpy(tbfuncionesClient[cf].nf, "NoComandosPtes"); + tbfuncionesClient[cf++].fptr = &NoComandosPtes; + + strcpy(tbfuncionesClient[cf].nf, "Actualizar"); + tbfuncionesClient[cf++].fptr = &Actualizar; + + strcpy(tbfuncionesClient[cf].nf, "Purgar"); + tbfuncionesClient[cf++].fptr = &Purgar; + + strcpy(tbfuncionesClient[cf].nf, "ConsolaRemota"); + tbfuncionesClient[cf++].fptr = &ConsolaRemota; + + strcpy(tbfuncionesClient[cf].nf, "Sondeo"); + tbfuncionesClient[cf++].fptr = &Sondeo; + + strcpy(tbfuncionesClient[cf].nf, "Arrancar"); + tbfuncionesClient[cf++].fptr = &Arrancar; + + strcpy(tbfuncionesClient[cf].nf, "Apagar"); + tbfuncionesClient[cf++].fptr = &Apagar; + + strcpy(tbfuncionesClient[cf].nf, "Reiniciar"); + tbfuncionesClient[cf++].fptr = &Reiniciar; + + strcpy(tbfuncionesClient[cf].nf, "IniciarSesion"); + tbfuncionesClient[cf++].fptr = &IniciarSesion; + + strcpy(tbfuncionesClient[cf].nf, "CrearImagen"); + tbfuncionesClient[cf++].fptr = &CrearImagen; + + strcpy(tbfuncionesClient[cf].nf, "CrearImagenBasica"); + tbfuncionesClient[cf++].fptr = &CrearImagenBasica; + + strcpy(tbfuncionesClient[cf].nf, "CrearSoftIncremental"); + tbfuncionesClient[cf++].fptr = &CrearSoftIncremental; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarImagen"); + tbfuncionesClient[cf++].fptr = &RestaurarImagen; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarImagenBasica"); + tbfuncionesClient[cf++].fptr = &RestaurarImagenBasica; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarSoftIncremental"); + tbfuncionesClient[cf++].fptr = &RestaurarSoftIncremental; + + + strcpy(tbfuncionesClient[cf].nf, "Configurar"); + tbfuncionesClient[cf++].fptr = &Configurar; + + strcpy(tbfuncionesClient[cf].nf, "EjecutarScript"); + tbfuncionesClient[cf++].fptr = &EjecutarScript; + + strcpy(tbfuncionesClient[cf].nf, "InventarioHardware"); + tbfuncionesClient[cf++].fptr = &InventarioHardware; + + strcpy(tbfuncionesClient[cf].nf, "InventarioSoftware"); + tbfuncionesClient[cf++].fptr = &InventarioSoftware; + + strcpy(tbfuncionesClient[cf].nf, "EjecutaComandosPendientes"); + tbfuncionesClient[cf++].fptr = &EjecutaComandosPendientes; + + /*-------------------------------------------------------------------------------------------------------- + Toma dirección IP del cliente + ---------------------------------------------------------------------------------------------------------*/ + if(!tomaIPlocal()){ // Error al recuperar la IP local + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Inicio de sesión + ---------------------------------------------------------------------------------------------------------*/ + infoLog(1); // Inicio de sesión + infoLog(3); // Abriendo sesión en el servidor de Administración; + /*-------------------------------------------------------------------------------------------------------- + Inclusión del cliente en el sistema + ---------------------------------------------------------------------------------------------------------*/ + if(!inclusionCliente(ptrTrama)){ // Ha habido algún problema al abrir sesión + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + infoLog(4); // Cliente iniciado + + /*-------------------------------------------------------------------------------------------------------- + Procesamiento de la cache + ---------------------------------------------------------------------------------------------------------*/ + infoLog(23); // Abriendo sesión en el servidor de Administración; + if(!cuestionCache(cache)){ + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Ejecución del autoexec + ---------------------------------------------------------------------------------------------------------*/ + if(atoi(idproautoexec)>0){ // Ejecución de procedimiento Autoexec + infoLog(5); + if(!autoexecCliente(ptrTrama)){ // Ejecución fichero autoexec + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + } + /*-------------------------------------------------------------------------------------------------------- + Comandos pendientes + ---------------------------------------------------------------------------------------------------------*/ + infoLog(6); // Procesa comandos pendientes + if(!comandosPendientes(ptrTrama)){ // Ejecución de acciones pendientes + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + infoLog(7); // Acciones pendientes procesadas + /*-------------------------------------------------------------------------------------------------------- + Bucle de recepción de comandos + ---------------------------------------------------------------------------------------------------------*/ + muestraMenu(); + procesaComandos(ptrTrama); // Bucle para procesar comandos interactivos + /*-------------------------------------------------------------------------------------------------------- + Fin de la sesión + ---------------------------------------------------------------------------------------------------------*/ + exit(EXIT_SUCCESS); +} diff --git a/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.h b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.h new file mode 100644 index 0000000..da0a5c3 --- /dev/null +++ b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.h @@ -0,0 +1,183 @@ +// ******************************************************************************************************** +// Cliernte: ogAdmClient +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmClient.h +// Descripción :Este fichero implementa el cliente general del sistema +// ******************************************************************************************************** +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ogAdmLib.h" +// ________________________________________________________________________________________________________ +// Variables globales +// ________________________________________________________________________________________________________ +char *idordenador; // Identificador del ordenador +char *nombreordenador; // Nombre del ordenador +char *cache; // Tamaño de la caché +char *idproautoexec; // Identificador del procedimiento de autoexec +char *idcentro; // Identificador de la Unidad Organizativa +char *idaula; // Identificador del aula +char IPlocal[LONIP]; // Ip local + +char servidoradm[LONPRM]; // Dirección IP del servidor de administración +char puerto[LONPRM]; // Puerto de comunicación +char pathinterface[LONPRM]; // Path donde está la interface entre la administración y el módulo de clonación + +char interface[LONFUN]; // Nombre del módulo,función o script de la interface con el módulo de administración +char parametros[LONSTD]; // Parámetros para la llamada +int herror; + +BOOLEAN CMDPTES; // Para bucle de comandos pendientes + + +char urlmenu[MAXLONURL]; // Url de la pagina de menu para el browser +char urlmsg[MAXLONURL]; // Url de la página de mensajed para el browser + + +typedef struct{ // Estructura usada para referenciar las funciones que procesan las tramas + char nf[LONFUN]; // Nombre de la función + BOOLEAN (*fptr)(TRAMA*); // Puntero a la función que procesa la trama +}MSGFUN; +MSGFUN tbfuncionesClient[MAXIMAS_FUNCIONES]; +// ________________________________________________________________________________________________________ +// Tabla de errores de la ejecución de los scripts +// ________________________________________________________________________________________________________ +char* tbErroresScripts[]={"Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo",\ + "001-Formato de ejecución incorrecto.",\ + "002-Fichero o dispositivo no encontrado",\ + "003-Error en partición de disco",\ + "004-Partición o fichero bloqueado",\ + "005-Error al crear o restaurar una imagen",\ + "006-Sin sistema operativo",\ + "007-Programa o función BOOLEAN no ejecutable",\ + "008-Error en la creación del archivo de eco para consola remota",\ + "009-Error en la lectura del archivo temporal de intercambio",\ + "010-Error al ejecutar la llamada a la interface de administración",\ + "011-La información retornada por la interface de administración excede de la longitud permitida",\ + "012-Error en el envío de fichero por la red",\ + "013-Error en la creación del proceso hijo",\ + "014-Error de escritura en destino",\ + "015-Sin Cache en el Cliente",\ + "016-No hay espacio en la cache para almacenar fichero-imagen",\ + "017-Error al Reducir el Sistema Archivos",\ + "018-Error al Expandir el Sistema Archivos",\ + "019-Valor fuera de rango o no válido.",\ + "020-Sistema de archivos desconocido o no se puede montar",\ + "021-Error en partición de caché local",\ + "022-El disco indicado no contiene una particion GPT",\ + "023-Error no definido",\ + "024-Error no definido",\ + "025-Error no definido",\ + "026-Error no definido",\ + "027-Error no definido",\ + "028-Error no definido",\ + "029-Error no definido",\ + "030-Error al restaurar imagen - Imagen mas grande que particion",\ + "031-Error al realizar el comando updateCache",\ + "032-Error al formatear",\ + "033-Archivo de imagen corrupto o de otra versión de partclone",\ + "034-Error no definido",\ + "035-Error no definido",\ + "036-Error no definido",\ + "037-Error no definido",\ + "038-Error no definido",\ + "039-Error no definido",\ + "040-Error imprevisto no definido",\ + "041-Error no definido",\ + "042-Error no definido",\ + "043-Error no definido",\ + "044-Error no definido",\ + "045-Error no definido",\ + "046-Error no definido",\ + "047-Error no definido",\ + "048-Error no definido",\ + "049-Error no definido",\ + "050-Error en la generación de sintaxis de transferenica unicast",\ + "051-Error en envio UNICAST de una particion",\ + "052-Error en envio UNICAST de un fichero",\ + "053-Error en la recepcion UNICAST de una particion",\ + "054-Error en la recepcion UNICAST de un fichero",\ + "055-Error en la generacion de sintaxis de transferenica Multicast",\ + "056-Error en envio MULTICAST de un fichero",\ + "057-Error en la recepcion MULTICAST de un fichero",\ + "058-Error en envio MULTICAST de una particion",\ + "059-Error en la recepcion MULTICAST de una particion",\ + "060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER",\ + "061-Error no definido",\ + "062-Error no definido",\ + "063-Error no definido",\ + "064-Error no definido",\ + "065-Error no definido",\ + "066-Error no definido",\ + "067-Error no definido",\ + "068-Error no definido",\ + "069-Error no definido",\ + "070-Error al montar una imagen sincronizada.",\ + "071-Imagen no sincronizable (es monolitica).",\ + "072-Error al desmontar la imagen.",\ + "073-No se detectan diferencias entre la imagen basica y la particion.",\ + "074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.",\ + "Error desconocido " + }; + #define MAXERRORSCRIPT 74 // Error máximo cometido +// ________________________________________________________________________________________________________ +// Prototipo de funciones +// ________________________________________________________________________________________________________ +BOOLEAN autoexecCliente(TRAMA*); +BOOLEAN RESPUESTA_AutoexecCliente(TRAMA*); +void procesaComandos(TRAMA*); + +BOOLEAN tomaConfiguracion(char*); +BOOLEAN tomaIPlocal(void); +void scriptLog(const char *,int ); + +BOOLEAN gestionaTrama(TRAMA *); +BOOLEAN inclusionCliente(); +char* LeeConfiguracion(); +BOOLEAN RESPUESTA_InclusionCliente(TRAMA *); + +BOOLEAN comandosPendientes(TRAMA*); +BOOLEAN NoComandosPtes(TRAMA *); + +BOOLEAN respuestaEjecucionComando(TRAMA *,int,char*); +BOOLEAN Sondeo(TRAMA *); +BOOLEAN Actualizar(TRAMA *); +int Purgar(TRAMA* ); + +BOOLEAN ConsolaRemota(TRAMA*); + +BOOLEAN Arrancar(TRAMA *); +BOOLEAN Apagar(TRAMA *); +BOOLEAN Reiniciar(TRAMA *); +BOOLEAN IniciarSesion(TRAMA *); +BOOLEAN CrearImagen(TRAMA *); +BOOLEAN CrearImagenBasica(TRAMA *); +BOOLEAN CrearSoftIncremental(TRAMA*); + +BOOLEAN InventarioHardware(TRAMA *); +BOOLEAN InventariandoSoftware(TRAMA *,BOOLEAN,char*); +BOOLEAN EjecutarScript(TRAMA *); +BOOLEAN ejecutaArchivo(char*,TRAMA*); + +BOOLEAN cuestionCache(char*); +int cargaPaginaWeb(char *); +void muestraMenu(void); +void muestraMensaje(int idx,char*); + +BOOLEAN enviaMensajeServidor(SOCKET *,TRAMA *,char); + + + + diff --git a/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.o b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.o new file mode 100644 index 0000000..e8bec64 Binary files /dev/null and b/native/Sources/Clients/ogAdmClient/sources/ogAdmClient.o differ diff --git a/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_all.deb b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_all.deb new file mode 100644 index 0000000..e64878a Binary files /dev/null and b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_all.deb differ diff --git a/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.buildinfo b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.buildinfo new file mode 100644 index 0000000..d2b2392 --- /dev/null +++ b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.buildinfo @@ -0,0 +1,182 @@ +Format: 1.0 +Source: ogagent-oglive +Binary: ogagent-oglive +Architecture: all +Version: 3.0.0-20190520 +Checksums-Md5: + 7252ce182f6ea1d1c6d569046770cbad 33624 ogagent-oglive_3.0.0-20190520_all.deb +Checksums-Sha1: + 5c1a1984bc7598e33a4271d11954352a77adda50 33624 ogagent-oglive_3.0.0-20190520_all.deb +Checksums-Sha256: + 94624c2751b6178a9476ee57a5f59c98f516cf5795f849383418a4182644dd0d 33624 ogagent-oglive_3.0.0-20190520_all.deb +Build-Origin: Ubuntu +Build-Architecture: amd64 +Build-Date: Thu, 14 Dec 2023 08:28:43 +0100 +Build-Tainted-By: + merged-usr-via-aliased-dirs + usr-local-has-configs + usr-local-has-libraries + usr-local-has-programs +Installed-Build-Depends: + autoconf (= 2.71-2), + automake (= 1:1.16.5-1.3), + autopoint (= 0.21-4ubuntu4), + autotools-dev (= 20220109.1), + base-files (= 12ubuntu4.4), + base-passwd (= 3.5.52build1), + bash (= 5.1-6ubuntu1), + binutils (= 2.38-4ubuntu2.4), + binutils-common (= 2.38-4ubuntu2.4), + binutils-x86-64-linux-gnu (= 2.38-4ubuntu2.4), + bsdextrautils (= 2.37.2-4ubuntu3), + bsdutils (= 1:2.37.2-4ubuntu3), + build-essential (= 12.9ubuntu3), + bzip2 (= 1.0.8-5build1), + coreutils (= 8.32-4.1ubuntu1), + cpp (= 4:11.2.0-1ubuntu1), + cpp-11 (= 11.4.0-1ubuntu1~22.04), + dash (= 0.5.11+git20210903+057cd650a4ed-3build1), + debconf (= 1.5.79ubuntu1), + debhelper (= 13.6ubuntu1), + debianutils (= 5.5-1ubuntu2), + debugedit (= 1:5.0-4build1), + dh-autoreconf (= 20), + dh-strip-nondeterminism (= 1.13.0-1), + diffutils (= 1:3.8-0ubuntu2), + dpkg (= 1.21.1ubuntu2.2), + dpkg-dev (= 1.21.1ubuntu2.2), + dwz (= 0.14-1build2), + file (= 1:5.41-3ubuntu0.1), + findutils (= 4.8.0-1ubuntu3), + g++ (= 4:11.2.0-1ubuntu1), + g++-11 (= 11.4.0-1ubuntu1~22.04), + gawk (= 1:5.1.0-1ubuntu0.1), + gcc (= 4:11.2.0-1ubuntu1), + gcc-11 (= 11.4.0-1ubuntu1~22.04), + gcc-11-base (= 11.4.0-1ubuntu1~22.04), + gcc-12-base (= 12.3.0-1ubuntu1~22.04), + gettext (= 0.21-4ubuntu4), + gettext-base (= 0.21-4ubuntu4), + grep (= 3.7-1build1), + groff-base (= 1.22.4-8build1), + gzip (= 1.10-4ubuntu4.1), + hostname (= 3.23ubuntu2), + init-system-helpers (= 1.62), + install-info (= 6.8-4build1), + intltool-debian (= 0.35.0+20060710.5), + libacl1 (= 2.3.1-1), + libarchive-zip-perl (= 1.68-1), + libasan6 (= 11.4.0-1ubuntu1~22.04), + libatomic1 (= 12.3.0-1ubuntu1~22.04), + libattr1 (= 1:2.5.1-1build1), + libaudit-common (= 1:3.0.7-1build1), + libaudit1 (= 1:3.0.7-1build1), + libbinutils (= 2.38-4ubuntu2.4), + libblkid1 (= 2.37.2-4ubuntu3), + libbz2-1.0 (= 1.0.8-5build1), + libc-bin (= 2.35-0ubuntu3.5), + libc-dev-bin (= 2.35-0ubuntu3.5), + libc6 (= 2.35-0ubuntu3.5), + libc6-dev (= 2.35-0ubuntu3.5), + libcap-ng0 (= 0.7.9-2.2build3), + libcap2 (= 1:2.44-1ubuntu0.22.04.1), + libcc1-0 (= 12.3.0-1ubuntu1~22.04), + libcom-err2 (= 1.46.5-2ubuntu1.1), + libcrypt-dev (= 1:4.4.27-1), + libcrypt1 (= 1:4.4.27-1), + libctf-nobfd0 (= 2.38-4ubuntu2.4), + libctf0 (= 2.38-4ubuntu2.4), + libdb5.3 (= 5.3.28+dfsg1-0.8ubuntu3), + libdebconfclient0 (= 0.261ubuntu1), + libdebhelper-perl (= 13.6ubuntu1), + libdpkg-perl (= 1.21.1ubuntu2.2), + libdw1 (= 0.186-1build1), + libelf1 (= 0.186-1build1), + libfile-stripnondeterminism-perl (= 1.13.0-1), + libgcc-11-dev (= 11.4.0-1ubuntu1~22.04), + libgcc-s1 (= 12.3.0-1ubuntu1~22.04), + libgcrypt20 (= 1.9.4-3ubuntu3), + libgdbm-compat4 (= 1.23-1), + libgdbm6 (= 1.23-1), + libgmp10 (= 2:6.2.1+dfsg-3ubuntu1), + libgomp1 (= 12.3.0-1ubuntu1~22.04), + libgpg-error0 (= 1.43-3), + libgssapi-krb5-2 (= 1.19.2-2ubuntu0.3), + libicu70 (= 70.1-2), + libisl23 (= 0.24-2build1), + libitm1 (= 12.3.0-1ubuntu1~22.04), + libk5crypto3 (= 1.19.2-2ubuntu0.3), + libkeyutils1 (= 1.6.1-2ubuntu3), + libkrb5-3 (= 1.19.2-2ubuntu0.3), + libkrb5support0 (= 1.19.2-2ubuntu0.3), + liblsan0 (= 12.3.0-1ubuntu1~22.04), + liblz4-1 (= 1.9.3-2build2), + liblzma5 (= 5.2.5-2ubuntu1), + libmagic-mgc (= 1:5.41-3ubuntu0.1), + libmagic1 (= 1:5.41-3ubuntu0.1), + libmount1 (= 2.37.2-4ubuntu3), + libmpc3 (= 1.2.1-2build1), + libmpfr6 (= 4.1.0-3build3), + libnsl-dev (= 1.3.0-2build2), + libnsl2 (= 1.3.0-2build2), + libpam-modules (= 1.4.0-11ubuntu2.3), + libpam-modules-bin (= 1.4.0-11ubuntu2.3), + libpam-runtime (= 1.4.0-11ubuntu2.3), + libpam0g (= 1.4.0-11ubuntu2.3), + libpcre2-8-0 (= 10.40-1+ubuntu22.04.1+deb.sury.org+1), + libpcre3 (= 2:8.45-1+ubuntu22.04.1+deb.sury.org+1), + libperl5.34 (= 5.34.0-3ubuntu1.3), + libpipeline1 (= 1.5.5-1), + libquadmath0 (= 12.3.0-1ubuntu1~22.04), + libreadline8 (= 8.1.2-1), + libseccomp2 (= 2.5.3-2ubuntu2), + libselinux1 (= 3.3-1build2), + libsigsegv2 (= 2.13-1ubuntu3), + libsmartcols1 (= 2.37.2-4ubuntu3), + libssl3 (= 3.0.2-0ubuntu1.12), + libstdc++-11-dev (= 11.4.0-1ubuntu1~22.04), + libstdc++6 (= 12.3.0-1ubuntu1~22.04), + libsub-override-perl (= 0.09-2), + libsystemd0 (= 249.11-0ubuntu3.11), + libtinfo6 (= 6.3-2ubuntu0.1), + libtirpc-common (= 1.3.2-2ubuntu0.1), + libtirpc-dev (= 1.3.2-2ubuntu0.1), + libtirpc3 (= 1.3.2-2ubuntu0.1), + libtool (= 2.4.6-15build2), + libtsan0 (= 11.4.0-1ubuntu1~22.04), + libubsan1 (= 12.3.0-1ubuntu1~22.04), + libuchardet0 (= 0.0.7-1build2), + libudev1 (= 249.11-0ubuntu3.11), + libunistring2 (= 1.0-1), + libuuid1 (= 2.37.2-4ubuntu3), + libxml2 (= 2.9.14+dfsg-0.1+ubuntu22.04.1+deb.sury.org+1), + libzstd1 (= 1.4.8+dfsg-3build1), + linux-libc-dev (= 5.15.0-91.101), + login (= 1:4.8.1-2ubuntu2.1), + lsb-base (= 11.1.0ubuntu4), + lto-disabled-list (= 24), + m4 (= 1.4.18-5ubuntu2), + make (= 4.3-4.1build1), + man-db (= 2.10.2-1), + mawk (= 1.3.4.20200120-3), + ncurses-base (= 6.3-2ubuntu0.1), + ncurses-bin (= 6.3-2ubuntu0.1), + patch (= 2.7.6-7build2), + perl (= 5.34.0-3ubuntu1.3), + perl-base (= 5.34.0-3ubuntu1.3), + perl-modules-5.34 (= 5.34.0-3ubuntu1.3), + po-debconf (= 1.0.21+nmu1), + readline-common (= 8.1.2-1), + rpcsvc-proto (= 1.4.2-0ubuntu6), + sed (= 4.8-1ubuntu2), + sensible-utils (= 0.0.17), + sysvinit-utils (= 3.01-1ubuntu1), + tar (= 1.34+dfsg-1ubuntu0.1.22.04.2), + util-linux (= 2.37.2-4ubuntu3), + xz-utils (= 5.2.5-2ubuntu1), + zlib1g (= 1:1.2.11.dfsg-2ubuntu9.2) +Environment: + DEB_BUILD_OPTIONS="parallel=8" + DEB_BUILD_PROFILES="noudeb" + LANG="C" + SOURCE_DATE_EPOCH="1529319600" diff --git a/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.changes b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.changes new file mode 100644 index 0000000..9ab26d9 --- /dev/null +++ b/native/Sources/Clients/ogagent/ogagent-oglive_3.0.0-20190520_amd64.changes @@ -0,0 +1,26 @@ +Format: 1.8 +Date: Mon, 18 Jun 2018 13:00:00 +0200 +Source: ogagent-oglive +Binary: ogagent-oglive +Built-For-Profiles: noudeb +Architecture: all +Version: 3.0.0-20190520 +Distribution: unstable +Urgency: medium +Maintainer: Ramón M. Gómez +Changed-By: Ramón M. Gómez +Description: + ogagent-oglive - OpenGnsys Agent for ogLive client +Changes: + ogagent-oglive (3.0.0-20190520) unstable; urgency=medium + . + * OGAgent for ogLive compatible with OpenGnsys 3 web API +Checksums-Sha1: + 5c1a1984bc7598e33a4271d11954352a77adda50 33624 ogagent-oglive_3.0.0-20190520_all.deb + ec6e0da3760059612e014f25297cb73e887697cd 5954 ogagent-oglive_3.0.0-20190520_amd64.buildinfo +Checksums-Sha256: + 94624c2751b6178a9476ee57a5f59c98f516cf5795f849383418a4182644dd0d 33624 ogagent-oglive_3.0.0-20190520_all.deb + 7f2a8b5e25860c53c72b1a438010be022b3bf1c0a05f3562b570f9e940bfd450 5954 ogagent-oglive_3.0.0-20190520_amd64.buildinfo +Files: + 7252ce182f6ea1d1c6d569046770cbad 33624 admin optional ogagent-oglive_3.0.0-20190520_all.deb + 9f2806400070d5df4bb4c54a010dde70 5954 admin optional ogagent-oglive_3.0.0-20190520_amd64.buildinfo diff --git a/native/Sources/Clients/ogagent/oglive/build-stamp b/native/Sources/Clients/ogagent/oglive/build-stamp new file mode 100644 index 0000000..e69de29 diff --git a/native/Sources/Clients/ogagent/oglive/configure-stamp b/native/Sources/Clients/ogagent/oglive/configure-stamp new file mode 100644 index 0000000..e69de29 diff --git a/native/Sources/Clients/ogagent/oglive/debian/.debhelper/generated/ogagent-oglive/installed-by-dh_installdocs b/native/Sources/Clients/ogagent/oglive/debian/.debhelper/generated/ogagent-oglive/installed-by-dh_installdocs new file mode 100644 index 0000000..e4fdbda --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/.debhelper/generated/ogagent-oglive/installed-by-dh_installdocs @@ -0,0 +1 @@ +./readme.txt diff --git a/native/Sources/Clients/ogagent/oglive/debian/files b/native/Sources/Clients/ogagent/oglive/debian/files new file mode 100644 index 0000000..a00cd9d --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/files @@ -0,0 +1,2 @@ +ogagent-oglive_3.0.0-20190520_all.deb admin optional +ogagent-oglive_3.0.0-20190520_amd64.buildinfo admin optional diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.debhelper.log b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.debhelper.log new file mode 100644 index 0000000..908d06e --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.debhelper.log @@ -0,0 +1,14 @@ +dh_prep +dh_installdirs +dh_installchangelogs +dh_installdocs +dh_installdebconf +dh_installinit +dh_compress +dh_link +dh_fixperms +dh_installdeb +dh_shlibdeps +dh_gencontrol +dh_md5sums +dh_builddeb diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/control b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/control new file mode 100644 index 0000000..719a066 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/control @@ -0,0 +1,11 @@ +Package: ogagent-oglive +Version: 3.0.0-20190520 +Architecture: all +Maintainer: Ramón M. Gómez +Installed-Size: 235 +Depends: python-requests (>= 0.8.2), python-six (>= 1.1), python-prctl (>= 1.1.1), python (>= 2.7), libxss1 +Section: admin +Priority: optional +Homepage: https://opengnsys.es +Description: OpenGnsys Agent for ogLive client + This package provides the required components to allow this machine to work on an environment managed by OpenGnsys. diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/md5sums b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/md5sums new file mode 100644 index 0000000..319e0b8 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/md5sums @@ -0,0 +1,44 @@ +a645b097e936b35a0f9d667320b97c7a usr/bin/ogagent +f1af20ebcb0f9ca24050f5440b280971 usr/share/OGAgent/cfg/ogagent.cfg +1a151168042f9f91b0ac9de8d81b1cc9 usr/share/OGAgent/cfg/ogclient.cfg +e9b55cf5a2893cb205ece2914ad2cec6 usr/share/OGAgent/opengnsys/RESTApi.py +b2145636e0e9f3733a07dc3c864ffba6 usr/share/OGAgent/opengnsys/__init__.py +a53a553fabe11b358872eaa6f15e51c7 usr/share/OGAgent/opengnsys/certs.py +b6b6d13dffe43f62019489701bd3dceb usr/share/OGAgent/opengnsys/config.py +5ddd04ea082b0030b56dbac442817ba2 usr/share/OGAgent/opengnsys/httpserver.py +a7ceb4791ea9a1e5074f37c27aaef65b usr/share/OGAgent/opengnsys/ipc.py +08005cd7b24449275157d9c560f729c0 usr/share/OGAgent/opengnsys/linux/OGAgentService.py +3ef55d64ebda86651c3d882c5c649389 usr/share/OGAgent/opengnsys/linux/__init__.py +e5c7da55543002f86d591d243383563a usr/share/OGAgent/opengnsys/linux/daemon.py +86e7674bddc118fc1ceb9cd1de7d5912 usr/share/OGAgent/opengnsys/linux/log.py +18c89c3f7a9d457f99c1e1bb9e3297dd usr/share/OGAgent/opengnsys/linux/operations.py +f287da160c9d182e8a11d86bce27fd69 usr/share/OGAgent/opengnsys/linux/renamer/__init__.py +dee0a162a35e6bf8b18e39c4b8c4922c usr/share/OGAgent/opengnsys/linux/renamer/debian.py +39cc52a365eac6caec10dbad16d3dceb usr/share/OGAgent/opengnsys/linux/renamer/opensuse.py +b97470f7d68208d837659fcd6b910c9f usr/share/OGAgent/opengnsys/linux/renamer/redhat.py +f2255a73b7801f9596a9929358d75629 usr/share/OGAgent/opengnsys/loader.py +8d648c5a0cbb79e69c3d0eeee8247226 usr/share/OGAgent/opengnsys/log.py +cc21354530aecfd1376d0a9efcedc0f5 usr/share/OGAgent/opengnsys/macos/__init__.py +5ed4af5272fe5f5e4bd1f5ad591edd3a usr/share/OGAgent/opengnsys/macos/operations.py +d41d8cd98f00b204e9800998ecf8427e usr/share/OGAgent/opengnsys/modules/__init__.py +5be7cd44bb941107cbe67345982cce22 usr/share/OGAgent/opengnsys/modules/client/OpenGnSys/__init__.py +d41d8cd98f00b204e9800998ecf8427e usr/share/OGAgent/opengnsys/modules/client/__init__.py +a7903db8bd76249a4e0ee72147542ecd usr/share/OGAgent/opengnsys/modules/server/OpenGnSys/__init__.py +d41d8cd98f00b204e9800998ecf8427e usr/share/OGAgent/opengnsys/modules/server/__init__.py +3ef55d64ebda86651c3d882c5c649389 usr/share/OGAgent/opengnsys/oglive/__init__.py +e5c7da55543002f86d591d243383563a usr/share/OGAgent/opengnsys/oglive/daemon.py +a316e2cd56e19eb453215d441f9589aa usr/share/OGAgent/opengnsys/oglive/operations.py +7b20385f798d849dd546eb1c25149d76 usr/share/OGAgent/opengnsys/operations.py +e5c055043531b106f345f63ffbfb3b44 usr/share/OGAgent/opengnsys/scriptThread.py +296542d5654398781ec99c1ec2c0db7f usr/share/OGAgent/opengnsys/service.py +68b513e35d67d3e783947ec35b60cfa7 usr/share/OGAgent/opengnsys/utils.py +99858b8c43e60816ce3d50888f6bdf21 usr/share/OGAgent/opengnsys/windows/OGAgentService.py +5c4822b3e4cef2d5ec2225ad8adcfeed usr/share/OGAgent/opengnsys/windows/__init__.py +737d49175b1b4045adfd3bd8a66b66b7 usr/share/OGAgent/opengnsys/windows/log.py +f6e9945941b22caf066617abc25b47e2 usr/share/OGAgent/opengnsys/windows/operations.py +4eeead8170a612cedd5ac16f043695f8 usr/share/OGAgent/opengnsys/workers/__init__.py +7e0279e56a6730c74c4b525916a06f57 usr/share/OGAgent/opengnsys/workers/client_worker.py +6e6ff6fc0e398882d8696ae00cf48bb9 usr/share/OGAgent/opengnsys/workers/server_worker.py +c25929437b6c40d24ff965ca588dd089 usr/share/doc/ogagent-oglive/changelog.Debian.gz +172f344346f66d22a8bf1888b1811c06 usr/share/doc/ogagent-oglive/copyright +a7d8603a8cfc9a45e52129a5e5e8664b usr/share/doc/ogagent-oglive/readme.txt diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postinst b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postinst new file mode 100755 index 0000000..8fc04b5 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postinst @@ -0,0 +1,21 @@ +#!/bin/sh + +. /usr/share/debconf/confmodule + +set -e +case "$1" in + configure) + chmod 600 /usr/share/OGAgent/cfg/ogagent.cfg + ;; + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + + + +exit 0 diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postrm b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postrm new file mode 100755 index 0000000..a46fa48 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/DEBIAN/postrm @@ -0,0 +1,10 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +set -e + +if [ "$1" = "purge" ] ; then + rm -rf /usr/share/OGAgent || true > /dev/null 2>&1 +fi + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogagent.cfg b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogagent.cfg new file mode 120000 index 0000000..8a21b68 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogagent.cfg @@ -0,0 +1 @@ +/usr/share/OGAgent/cfg/ogagent.cfg \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogclient.cfg b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogclient.cfg new file mode 120000 index 0000000..c7dfd07 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/etc/ogagent/ogclient.cfg @@ -0,0 +1 @@ +/usr/share/OGAgent/cfg/ogclient.cfg \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/bin/ogagent b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/bin/ogagent new file mode 100755 index 0000000..1bcc29b --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/bin/ogagent @@ -0,0 +1,6 @@ +#!/bin/sh + +FOLDER=/usr/share/OGAgent + +cd $FOLDER +python -m opengnsys.linux.OGAgentService $@ diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogagent.cfg b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogagent.cfg new file mode 100644 index 0000000..2c84cb1 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogagent.cfg @@ -0,0 +1,27 @@ +[opengnsys] +# Listen address & port of REST +address=0.0.0.0 +port=8000 + +# This is a comma separated list of paths where to look for modules to load +path=test_modules/server + +# Remote OpenGnsys Service (please change IP address) +remote=https://192.168.2.10/opengnsys/rest/v3 +# Alternate OpenGnsys Service (comment out to enable this option) +#altremote=https://10.0.2.2/opengnsys/rest + +# Security tokens (please change) +client=xxxxx +secret=yyyyy + +# Log Level, if ommited, will be set to INFO +log=DEBUG + +# Module specific +# The sections must match the module name +# This section will be passes on activation to module +#[Sample1] +#value1=Mariete +#value2=Yo +#remote=https://172.27.0.1:9999/rest diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogclient.cfg b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogclient.cfg new file mode 100644 index 0000000..d39fc96 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/cfg/ogclient.cfg @@ -0,0 +1,11 @@ +[opengnsys] +# Log Level, if ommited, will be set to INFO +log=DEBUG + +# Module specific +# The sections must match the module name +# This section will be passes on activation to module +#[Sample1] +#value1=Mariete +#value2=Yo +#remote=https://172.27.0.1:9999/rest diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/RESTApi.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/RESTApi.py new file mode 100644 index 0000000..39c23a9 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/RESTApi.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 201 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +@author: Adolfo Gómez, dkmaster at dkmon dot com +""" + +# pylint: disable-msg=E1101,W0703 + +from __future__ import unicode_literals + +import requests +import logging +import json +import warnings + +from .log import logger + +from .utils import exceptionToMessage + +VERIFY_CERT = False # Do not check server certificate +TIMEOUT = 5 # Connection timout, in seconds + + +class RESTError(Exception): + ERRCODE = 0 + + +class ConnectionError(RESTError): + ERRCODE = -1 + + +# Disable warnings log messages +try: + import urllib3 # @UnusedImport +except Exception: + from requests.packages import urllib3 # @Reimport + +try: + urllib3.disable_warnings() # @UndefinedVariable + warnings.simplefilter("ignore") +except Exception: + pass # In fact, isn't too important, but wil log warns to logging file + + +class REST(object): + """ + Simple interface to remote REST apis. + The constructor expects the "base url" as parameter, that is, the url that will be common on all REST requests + Remember that this is a helper for "easy of use". You can provide your owns using requests lib for example. + Examples: + v = REST('https://example.com/rest/v1/') (Can omit trailing / if desired) + v.sendMessage('hello?param1=1¶m2=2') + This will generate a GET message to https://example.com/rest/v1/hello?param1=1¶m2=2, and return the + deserialized JSON result or an exception + v.sendMessage('hello?param1=1¶m2=2', {'name': 'mario' }) + This will generate a POST message to https://example.com/rest/v1/hello?param1=1¶m2=2, with json encoded + body {'name': 'mario' }, and also returns + the deserialized JSON result or raises an exception in case of error + """ + access_token = None + refresh_token = None + + def __init__(self, url): + """ + Initializes the REST helper + url is the full url of the REST API Base, as for example "https://example.com/rest/v1". + @param url The url of the REST API Base. The trailing '/' can be included or omitted, as desired. + """ + self.endpoint = url + + if self.endpoint[-1] != '/': + self.endpoint += '/' + + # Some OSs ships very old python requests lib implementations, workaround them... + try: + self.newerRequestLib = requests.__version__.split('.')[0] >= '1' + except Exception: + self.newerRequestLib = False # I no version, guess this must be an old requests + + # Disable logging requests messages except for errors, ... + logging.getLogger("requests").setLevel(logging.CRITICAL) + # Tries to disable all warnings + try: + warnings.simplefilter("ignore") # Disables all warnings + except Exception: + pass + + def _getUrl(self, method): + """ + Internal method + Composes the URL based on "method" + @param method: Method to append to base url for composition + """ + url = self.endpoint + method + + return url + + def _request(self, url, data=None, patch=False): + """ + Launches the request + @param url: The url to obtain + @param data: if None, the request will be sent as a GET request. If != None, the request will be sent as a POST, + with data serialized as JSON in the body. + """ + try: + # Prepare the header content + headers = {'content-type': 'application/json'} + if self.access_token is not None: + headers['Authorization'] = 'Bearer ' + self.access_token + + if data is None: + logger.debug('REST - Requesting using GET (no data provided) {}'.format(url)) + # Old requests version does not support verify, but it do not checks ssl certificate by default + if self.newerRequestLib: + r = requests.get(url, verify=VERIFY_CERT, timeout=TIMEOUT) + else: + r = requests.get(url) + else: # POST / PATCH + if patch is False: + logger.debug('REST - Requesting using POST {}, data: {}'.format(url, data)) + if self.newerRequestLib: + r = requests.post(url, data=data, headers=headers, + verify=VERIFY_CERT, timeout=TIMEOUT) + else: + r = requests.post(url, data=data, headers=headers) + else: + logger.debug('REST - Requesting using PATCH {}, data: {}'.format(url, data)) + if self.newerRequestLib: + r = requests.patch(url, data=data, headers=headers, + verify=VERIFY_CERT, timeout=TIMEOUT) + else: + r = requests.patch(url, data=data, headers=headers) + + # la respuesta puede venir sin contenido, para ello miramos el codigo devuelto + if r.status_code == 204: + r = json.loads('{"response": "OK"}') + else: + r = json.loads(r.content) # Using instead of r.json() to make compatible with old requests lib versions + logger.debug("REST - response - " + json.dumps(r)) + except requests.exceptions.RequestException as e: + raise ConnectionError(e) + except Exception as e: + raise ConnectionError(exceptionToMessage(e)) + + return r + + def sendMessage(self, msg, data=None, processData=True, patch=False): + """ + Sends a message to remote REST server + @param data: if None or omitted, message will be a GET, else it will send a POST + @param processData: if True, data will be serialized to json before sending, else, data will be sent as "raw" + """ + logger.debug('Invoking post message {} with data {}'.format(msg, data)) + + if processData and data is not None: + data = json.dumps(data) + + url = self._getUrl(msg) + logger.debug('Requesting {}'.format(url)) + + return self._request(url, data, patch) + + def set_authorization_headers(self, access_token = None, refresh_token = None): + """ + Set access token and refresh token for use in REST Api with authorization headers + @param access_token: if None, no authorization headers will be sent in each request, else, and authorization header will be sent + @param refresh_token: if not None, when access_token expires, it will be used to obtain new access token + """ + self.access_token = access_token + self.refresh_token = refresh_token \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/__init__.py new file mode 100644 index 0000000..02e7c34 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/__init__.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +@author: Adolfo Gómez, dkmaster at dkmon dot com +""" +from __future__ import unicode_literals + +# On centos, old six release does not includes byte2int, nor six.PY2 +import six + +import modules +from RESTApi import REST, RESTError + +try: + with open('VERSION', 'r') as v: + VERSION = v.read() +except IOError: + VERSION = '1.1.0' + +__title__ = 'OpenGnsys Agent' +__version__ = VERSION +__build__ = 0x010750 +__author__ = 'Adolfo Gómez' +__license__ = "BSD 3-clause" +__copyright__ = "Copyright VirtualCable S.L.U." + +if not hasattr(six, 'byte2int'): + if six.PY3: + import operator + six.byte2int = operator.itemgetter(0) + else: + def _byte2int(bs): + return ord(bs[0]) + six.byte2int = _byte2int diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/certs.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/certs.py new file mode 100644 index 0000000..e4c070e --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/certs.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' + +from tempfile import gettempdir +from os.path import exists, join + +CERTFILE = 'OGAgent.pem' + + +def createSelfSignedCert(force=False): + + certFile = join(gettempdir(), CERTFILE) + + if exists(certFile) and not force: + return certFile + + certData = '''-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCb50K3mIznNklz +yVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxbfxHbeRnoYTWV2nKk4+tHqmvz +ujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqCfItWgL5pJopDpNHFul9Rn3ds +PMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPmVLdF4uJ3Tuz8TSy2gWLs5aSr +5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuDUGNBvBQFac1G7qUcMReeu8Zr +DUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDqDUK1Oqs9X35yOQfDOAFYHiix +PX0IsXOZAgMBAAECggEBAJi3000RrIUZUp6Ph0gzPMuCjDEEwWiQA7CPNX1gpb8O +dp0WhkDhUroWIaICYPSXtOwUTtVjRqivMoxPy1Thg3EIoGC/rdeSdlXRHMEGicwJ +yVyalFnatr5Xzg5wkxVh4XMd0zeDt7e3JD7s0QLo5lm1CEzd77qz6lhzFic5/1KX +bzdULtTlq60dazg2hEbcS4OmM1UMCtRVDAsOIUIZPL0M9j1C1d1iEdYnh2xshKeG +/GOfo95xsgdMlGjtv3hUT5ryKVoEsu+36rGb4VfhPfUvvoVbRx5QZpW+QvxaYh5E +Fi0JEROozFwG31Y++8El7J3yQko8cFBa1lYYUwwpNAECgYEAykT+GiM2YxJ4uVF1 +OoKiE9BD53i0IG5j87lGPnWqzEwYBwnqjEKDTou+uzMGz3MDV56UEFNho7wUWh28 +LpEkjJB9QgbsugjxIBr4JoL/rYk036e/6+U8I95lvYWrzb+rBMIkRDYI7kbQD/mQ +piYUpuCkTymNAu2RisK6bBzJslkCgYEAxVE23OQvkCeOV8hJNPZGpJ1mDS+TiOow +oOScMZmZpail181eYbAfMsCr7ri812lSj98NvA2GNVLpddil6LtS1cQ5p36lFBtV +xQUMZiFz4qVbEak+izL+vPaev/mXXsOcibAIQ+qI/0txFpNhJjpaaSy6vRCBYFmc +8pgSoBnBI0ECgYAUKCn2atnpp5aWSTLYgNosBU4vDA1PShD14dnJMaqyr0aZtPhF +v/8b3btFJoGgPMLxgWEZ+2U4ju6sSFhPf7FXvLJu2QfQRkHZRDbEh7t5DLpTK4Fp +va9vl6Ml7uM/HsGpOLuqfIQJUs87OFCc7iCSvMJDDU37I7ekT2GKkpfbCQKBgBrE +0NeY0WcSJrp7/oqD2sOcYurpCG/rrZs2SIZmGzUhMxaa0vIXzbO59dlWELB8pmnE +Tf20K//x9qA5OxDe0PcVPukdQlH+/1zSOYNliG44FqnHtyd1TJ/gKVtMBiAiE4uO +aSClod5Yosf4SJbCFd/s5Iyfv52NqsAyp1w3Aj/BAoGAVCnEiGUfyHlIR+UH4zZW +GXJMeqdZLfcEIszMxLePkml4gUQhoq9oIs/Kw+L1DDxUwzkXN4BNTlFbOSu9gzK1 +dhuIUGfS6RPL88U+ivC3A0y2jT43oUMqe3hiRt360UQ1GXzp2dMnR9odSRB1wHoO +IOjEBZ8341/c9ZHc5PCGAG8= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIJAIrEIthCfxUCMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD +VQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMREwDwYDVQQHDAhBbGNvcmNvbjEMMAoG +A1UECgwDVURTMQ4wDAYDVQQLDAVBY3RvcjESMBAGA1UEAwwJVURTIEFjdG9yMSgw +JgYJKoZIhvcNAQkBFhlzdXBwb3J0QHVkc2VudGVycHJpc2UuY29tMB4XDTE0MTAy +NjIzNDEyNFoXDTI0MTAyMzIzNDEyNFowgY0xCzAJBgNVBAYTAkVTMQ8wDQYDVQQI +DAZNYWRyaWQxETAPBgNVBAcMCEFsY29yY29uMQwwCgYDVQQKDANVRFMxDjAMBgNV +BAsMBUFjdG9yMRIwEAYDVQQDDAlVRFMgQWN0b3IxKDAmBgkqhkiG9w0BCQEWGXN1 +cHBvcnRAdWRzZW50ZXJwcmlzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCb50K3mIznNklzyVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxb +fxHbeRnoYTWV2nKk4+tHqmvzujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqC +fItWgL5pJopDpNHFul9Rn3dsPMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPm +VLdF4uJ3Tuz8TSy2gWLs5aSr5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuD +UGNBvBQFac1G7qUcMReeu8ZrDUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDq +DUK1Oqs9X35yOQfDOAFYHiixPX0IsXOZAgMBAAGjUDBOMB0GA1UdDgQWBBRShS90 +5lJTNvYPIEqP3GxWwG5iiDAfBgNVHSMEGDAWgBRShS905lJTNvYPIEqP3GxWwG5i +iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAU0Sp4gXhQmRVzq+7+ +vRFUkQuPj4Ga/d9r5Wrbg3hck3+5pwe9/7APoq0P/M0DBhQpiJKjrD6ydUevC+Y/ +43ZOJPhMlNw0o6TdQxOkX6FDwQanLLs7sfvJvqtVzYn3nuRFKT3dvl7Zg44QMw2M +ay42q59fAcpB4LaDx/i7gOYSS5eca3lYW7j7YSr/+ozXK2KlgUkuCUHN95lOq+dF +trmV9mjzM4CNPZqKSE7kpHRywgrXGPCO000NvEGSYf82AtgRSFKiU8NWLQSEPdcB +k//2dsQZw2cRZ8DrC2B6Tb3M+3+CA6wVyqfqZh1SZva3LfGvq/C+u+ItguzPqNpI +xtvM +-----END CERTIFICATE-----''' + with open(certFile, "wt") as f: + f.write(certData) + + return certFile diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/config.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/config.py new file mode 100644 index 0000000..d1f3ede --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/config.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +# pylint: disable=unused-wildcard-import, wildcard-import +from __future__ import unicode_literals + +from ConfigParser import SafeConfigParser + +config = None + +def readConfig(client=False): + ''' + Reads configuration file + If client is False, will read ogagent.cfg as configuration + If client is True, will read ogclient.cfg as configuration + + This is this way so we can protect ogagent.cfg against reading for non admin users on all platforms. + ''' + cfg = SafeConfigParser() + if client is True: + fname = 'ogclient.cfg' + else: + fname = 'ogagent.cfg' + + if len(cfg.read('cfg/{}'.format(fname))) == 0: + # No configuration found + return None + + return cfg + \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/httpserver.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/httpserver.py new file mode 100644 index 0000000..a06ae6b --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/httpserver.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +# pylint: disable=unused-wildcard-import,wildcard-import +from __future__ import unicode_literals, print_function + +# Pydev can't parse "six.moves.xxxx" because it is loaded lazy +import six +from six.moves.socketserver import ThreadingMixIn # @UnresolvedImport +from six.moves.BaseHTTPServer import BaseHTTPRequestHandler # @UnresolvedImport +from six.moves.BaseHTTPServer import HTTPServer # @UnresolvedImport +from six.moves.urllib.parse import unquote # @UnresolvedImport + +import json +import threading +import ssl + +from .utils import exceptionToMessage +from .certs import createSelfSignedCert +from .log import logger + +class HTTPServerHandler(BaseHTTPRequestHandler): + service = None + protocol_version = 'HTTP/1.0' + server_version = 'OpenGnsys Agent Server' + sys_version = '' + + def sendJsonError(self, code, message): + self.send_response(code) + self.send_header('Content-type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps({'error': message})) + return + + def sendJsonResponse(self, data): + self.send_response(200) + data = json.dumps(data) + self.send_header('Content-type', 'application/json') + self.send_header('Content-Length', len(data)) + self.end_headers() + # Send the html message + self.wfile.write(data) + + + # parseURL + def parseUrl(self): + # Very simple path & params splitter + path = self.path.split('?')[0][1:].split('/') + + try: + params = dict((v[0], unquote(v[1])) for v in (v.split('=') for v in self.path.split('?')[1].split('&'))) + except Exception: + params = {} + + for v in self.service.modules: + if v.name == path[0]: # Case Sensitive!!!! + return (v, path[1:], params) + + return (None, path, params) + + def notifyMessage(self, module, path, getParams, postParams): + ''' + Locates witch module will process the message based on path (first folder on url path) + ''' + try: + data = module.processServerMessage(path, getParams, postParams, self) + self.sendJsonResponse(data) + except Exception as e: + logger.exception() + self.sendJsonError(500, exceptionToMessage(e)) + + def do_GET(self): + module, path, params = self.parseUrl() + + self.notifyMessage(module, path, params, None) + + def do_POST(self): + module, path, getParams = self.parseUrl() + + # Tries to get JSON content (UTF-8 encoded) + try: + length = int(self.headers.getheader('content-length')) + content = self.rfile.read(length).decode('utf-8') + logger.debug('length: {}, content >>{}<<'.format(length, content)) + postParams = json.loads(content) + except Exception as e: + self.sendJsonError(500, exceptionToMessage(e)) + + self.notifyMessage(module, path, getParams, postParams) + + + def log_error(self, fmt, *args): + logger.error('HTTP ' + fmt % args) + + def log_message(self, fmt, *args): + logger.info('HTTP ' + fmt % args) + + +class HTTPThreadingServer(ThreadingMixIn, HTTPServer): + pass + +class HTTPServerThread(threading.Thread): + def __init__(self, address, service): + super(self.__class__, self).__init__() + + HTTPServerHandler.service = service # Keep tracking of service so we can intercact with it + + self.certFile = createSelfSignedCert() + self.server = HTTPThreadingServer(address, HTTPServerHandler) + self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True) + + logger.debug('Initialized HTTPS Server thread on {}'.format(address)) + + def getServerUrl(self): + return 'https://{}:{}/'.format(self.server.server_address[0], self.server.server_address[1]) + + def stop(self): + self.server.shutdown() + + def run(self): + self.server.serve_forever() + + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/ipc.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/ipc.py new file mode 100644 index 0000000..dd3663d --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/ipc.py @@ -0,0 +1,423 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import socket +import threading +import six +import traceback +import json + +from opengnsys.utils import toUnicode +from opengnsys.log import logger + +# The IPC Server will wait for connections from clients +# Clients will open socket, and wait for data from server +# The messages sent (from server) will be the following (subject to future changes): +# Message_id Data Action +# ------------ -------- -------------------------- +# MSG_LOGOFF None Logout user from session +# MSG_MESSAGE message,level Display a message with level (INFO, WARN, ERROR, FATAL) # TODO: Include level, right now only has message +# MSG_POPUP title,message Display a popup box with a title +# MSG_SCRIPT python script Execute an specific python script INSIDE CLIENT environment (this messages is not sent right now) +# The messages received (sent from client) will be the following: +# Message_id Data Action +# ------------ -------- -------------------------- +# REQ_LOGOUT Logout user from session +# REQ_INFORMATION None Request information from ipc server (maybe configuration parameters in a near future) +# REQ_LOGIN python script Execute an specific python script INSIDE CLIENT environment (this messages is not sent right now) +# +# All messages are in the form: +# BYTE +# 0 1-2 3 4 ... +# MSG_ID DATA_LENGTH (little endian) Data (can be 0 length) +# With a previos "MAGIC" header in fron of each message + +# Client messages +MSG_LOGOFF = 0xA1 # Request log off from an user +MSG_MESSAGE = 0xB2 +MSG_POPUP = 0xB3 +MSG_SCRIPT = 0xC3 + +# Request messages +REQ_MESSAGE = 0xD4 +REQ_POPUP = 0xD5 +REQ_LOGIN = 0xE5 +REQ_LOGOUT = 0xF6 + +# Reverse msgs dict for debugging +REV_DICT = { + MSG_LOGOFF: 'MSG_LOGOFF', + MSG_MESSAGE: 'MSG_MESSAGE', + MSG_POPUP: 'MSG_POPUP', + MSG_SCRIPT: 'MSG_SCRIPT', + REQ_LOGIN: 'REQ_LOGIN', + REQ_LOGOUT: 'REQ_LOGOUT', + REQ_MESSAGE: 'REQ_MESSAGE' +} + +MAGIC = b'\x4F\x47\x41\x00' # OGA in hexa with a padded 0 to the right + + +# States for client processor +ST_SECOND_BYTE = 0x01 +ST_RECEIVING = 0x02 +ST_PROCESS_MESSAGE = 0x02 + + +class ClientProcessor(threading.Thread): + def __init__(self, parent, clientSocket): + super(self.__class__, self).__init__() + self.parent = parent + self.clientSocket = clientSocket + self.running = False + self.messages = six.moves.queue.Queue(32) # @UndefinedVariable + + def stop(self): + logger.debug('Stoping client processor') + self.running = False + + def processRequest(self, msg, data): + logger.debug('Got Client message {}={}'.format(msg, REV_DICT.get(msg))) + if self.parent.clientMessageProcessor is not None: + self.parent.clientMessageProcessor(msg, data) + + def run(self): + self.running = True + self.clientSocket.setblocking(0) + + state = None + recv_msg = None + recv_data = None + while self.running: + try: + counter = 1024 + while counter > 0: # So we process at least the incoming queue every XX bytes readed + counter -= 1 + b = self.clientSocket.recv(1) + if b == b'': + # Client disconnected + self.running = False + break + buf = six.byte2int(b) # Empty buffer, this is set as non-blocking + if state is None: + if buf in (REQ_MESSAGE, REQ_LOGIN, REQ_LOGOUT): + logger.debug('State set to {}'.format(buf)) + state = buf + recv_msg = buf + continue # Get next byte + else: + logger.debug('Got unexpected data {}'.format(buf)) + elif state in (REQ_MESSAGE, REQ_LOGIN, REQ_LOGOUT): + logger.debug('First length byte is {}'.format(buf)) + msg_len = buf + state = ST_SECOND_BYTE + continue + elif state == ST_SECOND_BYTE: + msg_len += buf << 8 + logger.debug('Second length byte is {}, len is {}'.format(buf, msg_len)) + if msg_len == 0: + self.processRequest(recv_msg, None) + state = None + break + state = ST_RECEIVING + recv_data = b'' + continue + elif state == ST_RECEIVING: + recv_data += six.int2byte(buf) + msg_len -= 1 + if msg_len == 0: + self.processRequest(recv_msg, recv_data) + recv_data = None + state = None + break + else: + logger.debug('Got invalid message from request: {}, state: {}'.format(buf, state)) + except socket.error as e: + # If no data is present, no problem at all, pass to check messages + pass + except Exception as e: + tb = traceback.format_exc() + logger.error('Error: {}, trace: {}'.format(e, tb)) + + if self.running is False: + break + + try: + msg = self.messages.get(block=True, timeout=1) + except six.moves.queue.Empty: # No message got in time @UndefinedVariable + continue + + logger.debug('Got message {}={}'.format(msg, REV_DICT.get(msg[0]))) + + try: + m = msg[1] if msg[1] is not None else b'' + l = len(m) + data = MAGIC + six.int2byte(msg[0]) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + m + try: + self.clientSocket.sendall(data) + except socket.error as e: + # Send data error + logger.debug('Socket connection is no more available: {}'.format(e.args)) + self.running = False + except Exception as e: + logger.error('Invalid message in queue: {}'.format(e)) + + logger.debug('Client processor stopped') + try: + self.clientSocket.close() + except Exception: + pass # If can't close, nothing happens, just end thread + + +class ServerIPC(threading.Thread): + + def __init__(self, listenPort, clientMessageProcessor=None): + super(self.__class__, self).__init__() + self.port = listenPort + self.running = False + self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.threads = [] + self.clientMessageProcessor = clientMessageProcessor + + def stop(self): + logger.debug('Stopping Server IPC') + self.running = False + for t in self.threads: + t.stop() + socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect(('localhost', self.port)) + self.serverSocket.close() + + for t in self.threads: + t.join() + + def sendMessage(self, msgId, msgData): + ''' + Notify message to all listening threads + ''' + logger.debug('Sending message {}({}),{} to all clients'.format(msgId, REV_DICT.get(msgId), msgData)) + + # Convert to bytes so length is correctly calculated + if isinstance(msgData, six.text_type): + msgData = msgData.encode('utf8') + + for t in self.threads: + if t.isAlive(): + logger.debug('Sending to {}'.format(t)) + t.messages.put((msgId, msgData)) + + def sendLoggofMessage(self): + self.sendMessage(MSG_LOGOFF, '') + + def sendMessageMessage(self, message): + self.sendMessage(MSG_MESSAGE, message) + + def sendPopupMessage(self, title, message): + self.sendMessage(MSG_POPUP, {'title':title, 'message':message}) + + def sendScriptMessage(self, script): + self.sendMessage(MSG_SCRIPT, script) + + def cleanupFinishedThreads(self): + ''' + Cleans up current threads list + ''' + aliveThreads = [] + for t in self.threads: + if t.isAlive(): + logger.debug('Thread {} is alive'.format(t)) + aliveThreads.append(t) + self.threads[:] = aliveThreads + + def run(self): + self.running = True + + self.serverSocket.bind(('localhost', self.port)) + self.serverSocket.setblocking(1) + self.serverSocket.listen(4) + + while True: + try: + (clientSocket, address) = self.serverSocket.accept() + # Stop processing if thread is mean to stop + if self.running is False: + break + logger.debug('Got connection from {}'.format(address)) + + self.cleanupFinishedThreads() # House keeping + + logger.debug('Starting new thread, current: {}'.format(self.threads)) + t = ClientProcessor(self, clientSocket) + self.threads.append(t) + t.start() + except Exception as e: + logger.error('Got an exception on Server ipc thread: {}'.format(e)) + + +class ClientIPC(threading.Thread): + def __init__(self, listenPort): + super(ClientIPC, self).__init__() + self.port = listenPort + self.running = False + self.clientSocket = None + self.messages = six.moves.queue.Queue(32) # @UndefinedVariable + + self.connect() + + def stop(self): + self.running = False + + def getMessage(self): + while self.running: + try: + return self.messages.get(timeout=1) + except six.moves.queue.Empty: # @UndefinedVariable + continue + + return None + + def sendRequestMessage(self, msg, data=None): + logger.debug('Sending request for msg: {}({}), {}'.format(msg, REV_DICT.get(msg), data)) + if data is None: + data = b'' + + if isinstance(data, six.text_type): # Convert to bytes if necessary + data = data.encode('utf-8') + + l = len(data) + msg = six.int2byte(msg) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + data + self.clientSocket.sendall(msg) + + def sendLogin(self, username, language): + self.sendRequestMessage(REQ_LOGIN, username+','+language) + + def sendLogout(self, username): + self.sendRequestMessage(REQ_LOGOUT, username) + + def sendMessage(self, module, message, data=None): + ''' + Sends a message "message" with data (data will be encoded as json, so ensure that it is serializable) + @param module: Module that will receive this message + @param message: Message to send. This message is "customized", and understand by modules + @param data: Data to be send as message companion + ''' + msg = '\0'.join((module, message, json.dumps(data))) + self.sendRequestMessage(REQ_MESSAGE, msg) + + def messageReceived(self): + ''' + Override this method to automatically get notified on new message + received. Message is at self.messages queue + ''' + pass + + def receiveBytes(self, number): + msg = b'' + while self.running and len(msg) < number: + try: + buf = self.clientSocket.recv(number - len(msg)) + if buf == b'': + logger.debug('Buf {}, msg {}({})'.format(buf, msg, REV_DICT.get(msg))) + self.running = False + break + msg += buf + except socket.timeout: + pass + + if self.running is False: + logger.debug('Not running, returning None') + return None + return msg + + def connect(self): + self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.clientSocket.connect(('localhost', self.port)) + self.clientSocket.settimeout(2) # Static, custom socket timeout of 2 seconds for local connection (no network) + + def run(self): + self.running = True + + while self.running: + try: + msg = b'' + # We look for magic message header + while self.running: # Wait for MAGIC + try: + buf = self.clientSocket.recv(len(MAGIC) - len(msg)) + if buf == b'': + self.running = False + break + msg += buf + if len(msg) != len(MAGIC): + continue # Do not have message + if msg != MAGIC: # Skip first byte an continue searchong + msg = msg[1:] + continue + break + except socket.timeout: # Timeout is here so we can get stop thread + continue + + if self.running is False: + break + + # Now we get message basic data (msg + datalen) + msg = bytearray(self.receiveBytes(3)) + + # We have the magic header, here comes the message itself + if msg is None: + continue + + msgId = msg[0] + dataLen = msg[1] + (msg[2] << 8) + if msgId not in (MSG_LOGOFF, MSG_MESSAGE, MSG_SCRIPT): + raise Exception('Invalid message id: {}'.format(msgId)) + + data = self.receiveBytes(dataLen) + if data is None: + continue + + self.messages.put((msgId, data)) + self.messageReceived() + + except socket.error as e: + logger.error('Communication with server got an error: {}'.format(toUnicode(e.strerror))) + self.running = False + return + except Exception as e: + tb = traceback.format_exc() + logger.error('Error: {}, trace: {}'.format(e, tb)) + + try: + self.clientSocket.close() + except Exception: + pass # If can't close, nothing happens, just end thread + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/OGAgentService.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/OGAgentService.py new file mode 100644 index 0000000..29a238d --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/OGAgentService.py @@ -0,0 +1,147 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +from opengnsys.service import CommonService +from opengnsys.service import IPC_PORT +from opengnsys import ipc + +from opengnsys.log import logger + +from opengnsys.linux.daemon import Daemon + +import sys +import signal +import json + +try: + from prctl import set_proctitle # @UnresolvedImport +except Exception: # Platform may not include prctl, so in case it's not available, we let the "name" as is + def set_proctitle(_): + pass + + +class OGAgentSvc(Daemon, CommonService): + def __init__(self, args=None): + Daemon.__init__(self, '/var/run/opengnsys-agent.pid') + CommonService.__init__(self) + + def run(self): + logger.debug('** Running Daemon **') + set_proctitle('OGAgent') + + self.initialize() + + # Call modules initialization + # They are called in sequence, no threading is done at this point, so ensure modules onActivate always returns + + + # ********************* + # * Main Service loop * + # ********************* + # Counter used to check ip changes only once every 10 seconds, for + # example + try: + while self.isAlive: + # In milliseconds, will break + self.doWait(1000) + except (KeyboardInterrupt, SystemExit) as e: + logger.error('Requested exit of main loop') + except Exception as e: + logger.exception() + logger.error('Caught exception on main loop: {}'.format(e)) + + self.terminate() + + self.notifyStop() + + def signal_handler(self, signal, frame): + self.isAlive = False + sys.stderr.write("signal handler: {}".format(signal)) + + +def usage(): + sys.stderr.write("usage: {} start|stop|restart|fg|login 'username'|logout 'username'|message 'module' 'message' 'json'\n".format(sys.argv[0])) + sys.exit(2) + +if __name__ == '__main__': + logger.setLevel('INFO') + + if len(sys.argv) == 5 and sys.argv[1] == 'message': + logger.debug('Running client opengnsys') + client = None + try: + client = ipc.ClientIPC(IPC_PORT) + client.sendMessage(sys.argv[2], sys.argv[3], json.loads(sys.argv[4])) + sys.exit(0) + except Exception as e: + logger.error(e) + + + if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'): + logger.debug('Running client opengnsys') + client = None + try: + client = ipc.ClientIPC(IPC_PORT) + if 'login' == sys.argv[1]: + client.sendLogin(sys.argv[2]) + sys.exit(0) + elif 'logout' == sys.argv[1]: + client.sendLogout(sys.argv[2]) + sys.exit(0) + else: + usage() + except Exception as e: + logger.error(e) + elif len(sys.argv) != 2: + usage() + + logger.debug('Executing actor') + daemon = OGAgentSvc() + + signal.signal(signal.SIGTERM, daemon.signal_handler) + signal.signal(signal.SIGINT, daemon.signal_handler) + + if len(sys.argv) == 2: + if 'start' == sys.argv[1]: + daemon.start() + elif 'stop' == sys.argv[1]: + daemon.stop() + elif 'restart' == sys.argv[1]: + daemon.restart() + elif 'fg' == sys.argv[1]: + daemon.run() + else: + usage() + sys.exit(0) + else: + usage() diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/__init__.py new file mode 100644 index 0000000..3a98c78 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/daemon.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/daemon.py new file mode 100644 index 0000000..3753808 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/daemon.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: : http://www.jejik.com/authors/sander_marechal/ +@see: : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ +''' + +from __future__ import unicode_literals +import sys +import os +import time +import atexit +from opengnsys.log import logger + +from signal import SIGTERM + + +class Daemon: + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError as e: + logger.error("fork #1 error: {}".format(e)) + sys.stderr.write("fork #1 failed: {}\n".format(e)) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError as e: + logger.error("fork #2 error: {}".format(e)) + sys.stderr.write("fork #2 failed: {}\n".format(e)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = open(self.stdin, 'r') + so = open(self.stdout, 'a+') + se = open(self.stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + with open(self.pidfile, 'w+') as f: + f.write("{}\n".format(pid)) + + def delpid(self): + try: + os.remove(self.pidfile) + except Exception: + # Not found/not permissions or whatever... + pass + + def start(self): + """ + Start the daemon + """ + logger.debug('Starting daemon') + # Check for a pidfile to see if the daemon already runs + try: + pf = open(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile {} already exist. Daemon already running?\n".format(pid) + logger.error(message) + sys.stderr.write(message) + sys.exit(1) + + # Start the daemon + self.daemonize() + try: + self.run() + except Exception as e: + logger.error('Exception running process: {}'.format(e)) + + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = open(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid is None: + message = "pidfile {} does not exist. Daemon not running?\n".format(self.pidfile) + logger.info(message) + # sys.stderr.write(message) + return # not an error in a restart + + # Try killing the daemon process + try: + for i in range(10): + os.kill(pid, SIGTERM) + time.sleep(1) + except OSError as err: + if err.errno == 3: # No such process + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + sys.stderr.write(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + # Overridables + def run(self): + """ + You should override this method when you subclass Daemon. It will be called after the process has been + daemonized by start() or restart(). + """ diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/log.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/log.py new file mode 100644 index 0000000..dc54e19 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/log.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import logging +import os +import tempfile +import six + +# Valid logging levels, from UDS Broker (uds.core.utils.log) +OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xrange(6)) # @UndefinedVariable + + +class LocalLogger(object): + def __init__(self): + # tempdir is different for "user application" and "service" + # service wil get c:\windows\temp, while user will get c:\users\XXX\temp + # Try to open logger at /var/log path + # If it fails (access denied normally), will try to open one at user's home folder, and if + # agaim it fails, open it at the tmpPath + + for logDir in ('/var/log', os.path.expanduser('~'), tempfile.gettempdir()): + try: + fname = os.path.join(logDir, 'opengnsys.log') + logging.basicConfig( + filename=fname, + filemode='a', + format='%(levelname)s %(asctime)s %(message)s', + level=logging.DEBUG + ) + self.logger = logging.getLogger('opengnsys') + os.chmod(fname, 0o0600) + return + except Exception: + pass + + # Logger can't be set + self.logger = None + + def log(self, level, message): + # Debug messages are logged to a file + # our loglevels are 10000 (other), 20000 (debug), .... + # logging levels are 10 (debug), 20 (info) + # OTHER = logging.NOTSET + self.logger.log(int(level / 1000) - 10, message) + + def isWindows(self): + return False + + def isLinux(self): + return True diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/operations.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/operations.py new file mode 100644 index 0000000..db6ea18 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/operations.py @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import socket +import platform +import fcntl +import os +import locale +import ctypes # @UnusedImport +import ctypes.util +import subprocess +import struct +import array +import six +from opengnsys import utils +from .renamer import rename + + +def _getMacAddr(ifname): + ''' + Returns the mac address of an interface + Mac is returned as unicode utf-8 encoded + ''' + if isinstance(ifname, list): + return dict([(name, _getMacAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifname[:15]))) + return six.text_type(''.join(['%02x:' % char for char in info[18:24]])[:-1]) + except Exception: + return None + + +def _getIpAddr(ifname): + ''' + Returns the ip address of an interface + Ip is returned as unicode utf-8 encoded + ''' + if isinstance(ifname, list): + return dict([(name, _getIpAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + return six.text_type(socket.inet_ntoa(fcntl.ioctl( + s.fileno(), + 0x8915, # SIOCGIFADDR + struct.pack(str('256s'), ifname[:15]) + )[20:24])) + except Exception: + return None + + +def _getInterfaces(): + ''' + Returns a list of interfaces names coded in utf-8 + ''' + max_possible = 128 # arbitrary. raise if needed. + space = max_possible * 16 + if platform.architecture()[0] == '32bit': + offset, length = 32, 32 + elif platform.architecture()[0] == '64bit': + offset, length = 16, 40 + else: + raise OSError('Unknown arquitecture {0}'.format(platform.architecture()[0])) + + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + names = array.array(str('B'), b'\0' * space) + outbytes = struct.unpack(str('iL'), fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack(str('iL'), space, names.buffer_info()[0]) + ))[0] + namestr = names.tostring() + # return namestr, outbytes + return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)] + + +def _getIpAndMac(ifname): + ip, mac = _getIpAddr(ifname), _getMacAddr(ifname) + return (ip, mac) + + +def getComputerName(): + ''' + Returns computer name, with no domain + ''' + return socket.gethostname().split('.')[0] + + +def getNetworkInfo(): + ''' + Obtains a list of network interfaces + @return: A "generator" of elements, that are dict-as-object, with this elements: + name: Name of the interface + mac: mac of the interface + ip: ip of the interface + ''' + for ifname in _getInterfaces(): + ip, mac = _getIpAndMac(ifname) + if mac != '00:00:00:00:00:00': # Skips local interfaces + yield utils.Bunch(name=ifname, mac=mac, ip=ip) + + +def getDomainName(): + return '' + + +def getLinuxVersion(): + lv = platform.linux_distribution() + return lv[0] + ', ' + lv[1] + + +def reboot(flags=0): + ''' + Simple reboot using os command + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + subprocess.call(['/sbin/reboot']) + + +def poweroff(flags=0): + ''' + Simple poweroff using os command + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + subprocess.call(['/sbin/poweroff']) + + +def logoff(): + ''' + Kills all curent user processes, which must send a logogof + caveat: If the user has other sessions, will also disconnect from them + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + subprocess.call(['/usr/bin/pkill', '-u', os.environ['USER']]) + + +def renameComputer(newName): + rename(newName) + + +def joinDomain(domain, ou, account, password, executeInOneStep=False): + pass + + +def changeUserPassword(user, oldPassword, newPassword): + ''' + Simple password change for user using command line + ''' + os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword)) + + +class XScreenSaverInfo(ctypes.Structure): + _fields_ = [('window', ctypes.c_long), + ('state', ctypes.c_int), + ('kind', ctypes.c_int), + ('til_or_since', ctypes.c_ulong), + ('idle', ctypes.c_ulong), + ('eventMask', ctypes.c_ulong)] + +# Initialize xlib & xss +try: + xlibPath = ctypes.util.find_library('X11') + xssPath = ctypes.util.find_library('Xss') + xlib = ctypes.cdll.LoadLibrary(xlibPath) + xss = ctypes.cdll.LoadLibrary(xssPath) + + # Fix result type to XScreenSaverInfo Structure + xss.XScreenSaverQueryExtension.restype = ctypes.c_int + xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure +except Exception: # Libraries not accesible, not found or whatever.. + xlib = xss = None + + +def initIdleDuration(atLeastSeconds): + ''' + On linux we set the screensaver to at least required seconds, or we never will get "idle" + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]) + # And now reset it + subprocess.call(['/usr/bin/xset', 's', 'reset']) + + +def getIdleDuration(): + ''' + Returns idle duration, in seconds + ''' + if xlib is None or xss is None: + return 0 # Libraries not available + + # production code might want to not hardcode the offset 16... + display = xlib.XOpenDisplay(None) + + event_base = ctypes.c_int() + error_base = ctypes.c_int() + + available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base)) + if available != 1: + return 0 # No screen saver is available, no way of getting idle + + info = xss.XScreenSaverAllocInfo() + xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), info) + + if info.contents.state != 0: + return 3600 * 100 * 1000 # If screen saver is active, return a high enough value + + return info.contents.idle / 1000.0 + + +def getCurrentUser(): + ''' + Returns current logged in user + ''' + return os.environ['USER'] + + +def getSessionLanguage(): + ''' + Returns the user's session language + ''' + return locale.getdefaultlocale()[0] + + +def showPopup(title, message): + ''' + Displays a message box on user's session (during 1 min). + ''' + return subprocess.call('zenity --info --timeout 60 --title "{}" --text "{}"'.format(title, message), shell=True) + + +def get_etc_path(): + """ + :return: + Returns etc directory path. + """ + return os.sep + 'etc' diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/__init__.py new file mode 100644 index 0000000..27198dc --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/__init__.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import platform +import os +import sys +import pkgutil + +from opengnsys.log import logger + +renamers = {} + + +# Renamers now are for IPv4 only addresses +def rename(newName): + distribution = platform.linux_distribution()[0].lower().strip() + if distribution in renamers: + return renamers[distribution](newName) + + # Try Debian renamer, simplest one + logger.info('Renamer for platform "{0}" not found, tryin debian renamer'.format(distribution)) + return renamers['debian'](newName) + + +# Do load of packages +def _init(): + pkgpath = os.path.dirname(sys.modules[__name__].__file__) + for _, name, _ in pkgutil.iter_modules([pkgpath]): + __import__(__name__ + '.' + name, globals(), locals()) + +_init() \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/debian.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/debian.py new file mode 100644 index 0000000..be55e00 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/debian.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +from opengnsys.linux.renamer import renamers +from opengnsys.log import logger + +import os + + +def rename(newName): + ''' + Debian renamer + Expects new host name on newName + Host does not needs to be rebooted after renaming + ''' + logger.debug('using Debian renamer') + + with open('/etc/hostname', 'w') as hostname: + hostname.write(newName) + + # Force system new name + os.system('/bin/hostname %s' % newName) + + # add name to "hosts" + with open('/etc/hosts', 'r') as hosts: + lines = hosts.readlines() + with open('/etc/hosts', 'w') as hosts: + hosts.write("127.0.1.1\t%s\n" % newName) + for l in lines: + if l[:9] == '127.0.1.1': # Skips existing 127.0.1.1. if it already exists + continue + hosts.write(l) + + return True + +# All names in lower case +renamers['debian'] = rename +renamers['ubuntu'] = rename diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/opensuse.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/opensuse.py new file mode 100644 index 0000000..a2d29a5 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/opensuse.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +from opengnsys.linux.renamer import renamers +from opengnsys.log import logger + +import os + + +def rename(newName): + ''' + RH, Centos, Fedora Renamer + Expects new host name on newName + Host does not needs to be rebooted after renaming + ''' + logger.debug('using SUSE renamer') + + with open('/etc/hostname', 'w') as hostname: + hostname.write(newName) + + # Force system new name + os.system('/bin/hostname %s' % newName) + + # add name to "hosts" + with open('/etc/hosts', 'r') as hosts: + lines = hosts.readlines() + with open('/etc/hosts', 'w') as hosts: + hosts.write("127.0.1.1\t{}\n".format(newName)) + for l in lines: + if l[:9] != '127.0.1.1': # Skips existing 127.0.1.1. if it already exists + hosts.write(l) + + return True + +# All names in lower case +renamers['opensuse'] = rename +renamers['suse'] = rename diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/redhat.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/redhat.py new file mode 100644 index 0000000..8821a81 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/linux/renamer/redhat.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +from opengnsys.linux.renamer import renamers +from opengnsys.log import logger + +import os + + +def rename(newName): + ''' + RH, Centos, Fedora Renamer + Expects new host name on newName + Host does not needs to be rebooted after renaming + ''' + logger.debug('using RH renamer') + + with open('/etc/hostname', 'w') as hostname: + hostname.write(newName) + + # Force system new name + os.system('/bin/hostname %s' % newName) + + # add name to "hosts" + with open('/etc/hosts', 'r') as hosts: + lines = hosts.readlines() + with open('/etc/hosts', 'w') as hosts: + hosts.write("127.0.1.1\t{}\n".format(newName)) + for l in lines: + if l[:9] != '127.0.1.1': # Skips existing 127.0.1.1. if it already exists + hosts.write(l) + + with open('/etc/sysconfig/network', 'r') as net: + lines = net.readlines() + with open('/etc/sysconfig/network', 'w') as net: + net.write('HOSTNAME={}\n'.format(newName)) + for l in lines: + if l[:8] != 'HOSTNAME': + net.write(l) + + return True + +# All names in lower case +renamers['centos linux'] = rename +renamers['fedora'] = rename diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/loader.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/loader.py new file mode 100644 index 0000000..23988fc --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/loader.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +# pylint: disable=unused-wildcard-import,wildcard-import + +# This is a simple module loader, so we can add "external opengnsys" modules as addons +# Modules under "opengsnsys/modules" are always autoloaded +from __future__ import unicode_literals + +import pkgutil +import os.path + +from opengnsys.workers import ServerWorker +from opengnsys.workers import ClientWorker +from .log import logger + + +def loadModules(controller, client=False): + ''' + Load own provided modules plus the modules that are in the configuration path. + The loading order is not defined (they are loaded as found, because modules MUST be "standalone" modules + @param service: The service that: + * Holds the configuration + * Will be used to initialize modules. + ''' + + ogModules = [] + + if client is False: + from opengnsys.modules.server import OpenGnSys # @UnusedImport + from .modules import server # @UnusedImport, just used to ensure opengnsys modules are initialized + modPath = 'opengnsys.modules.server' + modType = ServerWorker + else: + from opengnsys.modules.client import OpenGnSys # @UnusedImport @Reimport + from .modules import client # @UnusedImport, just used to ensure opengnsys modules are initialized + modPath = 'opengnsys.modules.client' + modType = ClientWorker + + def addCls(cls): + logger.debug('Found module class {}'.format(cls)) + try: + if cls.name is None: + # Error, cls has no name + # Log the issue and + logger.error('Class {} has no name attribute'.format(cls)) + return + ogModules.append(cls(controller)) + except Exception as e: + logger.error('Error loading module {}'.format(e)) + + def recursiveAdd(p): + subcls = p.__subclasses__() + + if len(subcls) == 0: + addCls(p) + else: + for c in subcls: + recursiveAdd(c) + + def doLoad(paths): + for (module_loader, name, ispkg) in pkgutil.iter_modules(paths, modPath + '.'): + if ispkg: + logger.debug('Found module package {}'.format(name)) + module_loader.find_module(name).load_module(name) + + + if controller.config.has_option('opengnsys', 'path') is True: + paths = tuple(os.path.abspath(v) for v in controller.config.get('opengnsys', 'path').split(',')) + else: + paths = () + + # paths += (os.path.dirname(sys.modules[modPath].__file__),) + + logger.debug('Loading modules from {}'.format(paths)) + + # Load modules + doLoad(paths) + + # Add to list of available modules + recursiveAdd(modType) + + return ogModules diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/log.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/log.py new file mode 100644 index 0000000..e34c087 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/log.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import traceback +import sys +import six + +if sys.platform == 'win32': + from opengnsys.windows.log import LocalLogger # @UnusedImport +else: + from opengnsys.linux.log import LocalLogger # @Reimport + +# Valid logging levels, from UDS Broker (uds.core.utils.log) +OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xrange(6)) # @UndefinedVariable + +_levelName = { + 'OTHER': OTHER, + 'DEBUG': DEBUG, + 'INFO': INFO, + 'WARN': WARN, + 'ERROR': ERROR, + 'FATAL': FATAL +} + +class Logger(object): + def __init__(self): + self.logLevel = INFO + self.logger = LocalLogger() + + def setLevel(self, level): + ''' + Sets log level filter (minimum level required for a log message to be processed) + :param level: Any message with a level below this will be filtered out + ''' + if isinstance(level, six.string_types): + level = _levelName.get(level, INFO) + + self.logLevel = level # Ensures level is an integer or fails + + def log(self, level, message): + if level < self.logLevel: # Skip not wanted messages + return + + self.logger.log(level, message) + + def debug(self, message): + self.log(DEBUG, message) + + def warn(self, message): + self.log(WARN, message) + + def info(self, message): + self.log(INFO, message) + + def error(self, message): + self.log(ERROR, message) + + def fatal(self, message): + self.log(FATAL, message) + + def exception(self): + try: + tb = traceback.format_exc() + except Exception: + tb = '(could not get traceback!)' + + self.log(DEBUG, tb) + + def flush(self): + pass + + +logger = Logger() diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/__init__.py new file mode 100644 index 0000000..ee5ba4c --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Ramón M. Gómez, ramongomez at us dot es +''' +from __future__ import unicode_literals diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/operations.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/operations.py new file mode 100644 index 0000000..286b6d8 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/macos/operations.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import socket +import platform +import fcntl +import os +import locale +import ctypes # @UnusedImport +import ctypes.util +import subprocess +import struct +import array +import six +from opengnsys import utils +import netifaces + + +def _getMacAddr(ifname): + ''' + Returns the mac address of an interface + Mac is returned as unicode utf-8 encoded + ''' + if isinstance(ifname, list): + return dict([(name, _getMacAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + return netifaces.ifaddresses(ifname)[18][0]['addr'] + except Exception: + return None + + +def _getIpAddr(ifname): + ''' + Returns the IP address of an interface + IP is returned as unicode utf-8 encoded + ''' + if isinstance(ifname, list): + return dict([(name, _getIpAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + return netifaces.ifaddresses(ifname)[2][0]['addr'] + except Exception: + return None + + +def _getInterfaces(): + ''' + Returns a list of interfaces names + ''' + return netifaces.interfaces() + + +def _getIpAndMac(ifname): + ip, mac = _getIpAddr(ifname), _getMacAddr(ifname) + return (ip, mac) + + +def getComputerName(): + ''' + Returns computer name, with no domain + ''' + return socket.gethostname().split('.')[0] + + +def getNetworkInfo(): + ''' + Obtains a list of network interfaces + @return: A "generator" of elements, that are dict-as-object, with this elements: + name: Name of the interface + mac: mac of the interface + ip: ip of the interface + ''' + for ifname in _getInterfaces(): + ip, mac = _getIpAndMac(ifname) + if mac != None and ip != None: # Skips local interfaces + yield utils.Bunch(name=ifname, mac=mac, ip=ip) + + +def getDomainName(): + return '' + + +def getMacosVersion(): + return 'macOS {}'.format(platform.mac_ver()[0]) + + +def reboot(flags=0): + ''' + Simple reboot command + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + # Exec reboot command + subprocess.call('/sbin/shutdown -r now', shell=True) + + +def poweroff(flags=0): + ''' + Simple poweroff command + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + # Exec shutdown command + subprocess.call('/sbin/shutdown -h now', shell=True) + + +def logoff(): + ''' + Simple logout using AppleScript + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + # Exec logout using AppleSctipt + subprocess.call('/usr/bin/osascript -e \'tell app "System Events" to «event aevtrlgo»\'', shell=True) + + +def renameComputer(newName): + rename(newName) + + +def joinDomain(domain, ou, account, password, executeInOneStep=False): + pass + + +def changeUserPassword(user, oldPassword, newPassword): + ''' + Simple password change for user using command line + ''' + os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword)) + + +class XScreenSaverInfo(ctypes.Structure): + _fields_ = [('window', ctypes.c_long), + ('state', ctypes.c_int), + ('kind', ctypes.c_int), + ('til_or_since', ctypes.c_ulong), + ('idle', ctypes.c_ulong), + ('eventMask', ctypes.c_ulong)] + +# Initialize xlib & xss +try: + xlibPath = ctypes.util.find_library('X11') + xssPath = ctypes.util.find_library('Xss') + xlib = ctypes.cdll.LoadLibrary(xlibPath) + xss = ctypes.cdll.LoadLibrary(xssPath) + + # Fix result type to XScreenSaverInfo Structure + xss.XScreenSaverQueryExtension.restype = ctypes.c_int + xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure +except Exception: # Libraries not accesible, not found or whatever.. + xlib = xss = None + + +def initIdleDuration(atLeastSeconds): + ''' + On linux we set the screensaver to at least required seconds, or we never will get "idle" + ''' + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]) + # And now reset it + subprocess.call(['/usr/bin/xset', 's', 'reset']) + + +def getIdleDuration(): + ''' + Returns idle duration, in seconds + ''' + if xlib is None or xss is None: + return 0 # Libraries not available + + # production code might want to not hardcode the offset 16... + display = xlib.XOpenDisplay(None) + + event_base = ctypes.c_int() + error_base = ctypes.c_int() + + available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base)) + if available != 1: + return 0 # No screen saver is available, no way of getting idle + + info = xss.XScreenSaverAllocInfo() + xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), info) + + if info.contents.state != 0: + return 3600 * 100 * 1000 # If screen saver is active, return a high enough value + + return info.contents.idle / 1000.0 + + +def getCurrentUser(): + ''' + Returns current logged in user + ''' + return os.environ['USER'] + + +def getSessionLanguage(): + ''' + Returns the user's session language + ''' + return locale.getdefaultlocale()[0] + + +def showPopup(title, message): + ''' + Displays a message box on user's session (during 1 min). + ''' + # Show a dialog using AppleSctipt + return subprocess.call('/usr/bin/osascript -e \'display notification "{}" with title "{}"\''.format(message, title), shell=True) + + +def get_etc_path(): + """ + :return: + Returns etc directory path. + """ + return os.sep + 'etc' diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/client/OpenGnSys/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/client/OpenGnSys/__init__.py new file mode 100644 index 0000000..b840d92 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/client/OpenGnSys/__init__.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Ramón M. Gómez, ramongomez at us dot es +''' +from __future__ import unicode_literals + +from opengnsys.workers import ClientWorker + +from opengnsys import operations +from opengnsys.log import logger +from opengnsys.scriptThread import ScriptExecutorThread + +class OpenGnSysWorker(ClientWorker): + name = 'opengnsys' + + def onActivation(self): + logger.debug('Activate invoked') + + def onDeactivation(self): + logger.debug('Deactivate invoked') + + # Processes script execution + def process_script(self, jsonParams): + logger.debug('Processed message: script({})'.format(jsonParams)) + thr = ScriptExecutorThread(jsonParams['code']) + thr.start() + #self.sendServerMessage('script', {'op', 'launched'}) + + def process_logoff(self, jsonParams): + logger.debug('Processed message: logoff({})'.format(jsonParams)) + operations.logoff() + + def process_popup(self, jsonParams): + logger.debug('Processed message: popup({})'.format(jsonParams)) + ret = operations.showPopup(jsonParams['title'], jsonParams['message']) + #self.sendServerMessage('popup', {'op', ret}) + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/client/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/server/OpenGnSys/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/server/OpenGnSys/__init__.py new file mode 100644 index 0000000..223875a --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/server/OpenGnSys/__init__.py @@ -0,0 +1,558 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +@author: Ramón M. Gómez, ramongomez at us dot es +""" +from __future__ import unicode_literals + +import os +import random +import shutil +import string +import subprocess +import threading +import time +import urllib +import signal + +from opengnsys import REST +from opengnsys import operations +from opengnsys.log import logger +from opengnsys.workers import ServerWorker +from six.moves.urllib import parse + + +# Check authorization header decorator +def check_secret(fnc): + """ + Decorator to check for received secret key and raise exception if it isn't valid. + """ + def wrapper(*args, **kwargs): + try: + this, path, get_params, post_params, server = args # @UnusedVariable + if this.random == server.headers['Authorization']: + fnc(*args, **kwargs) + else: + raise Exception('Unauthorized operation') + except Exception as e: + logger.error(e) + raise Exception(e) + + return wrapper + + +# Error handler decorator. +def catch_background_error(fnc): + def wrapper(*args, **kwargs): + this = args[0] + try: + fnc(*args, **kwargs) + except Exception as e: + this.REST.sendMessage('error?id={}'.format(kwargs.get('requestId', 'error')), {'error': '{}'.format(e)}) + + return wrapper + + +def check_locked_partition(sync=False): + """ + Decorator to check if a partition is locked + """ + + def outer(fnc): + def wrapper(*args, **kwargs): + part_id = 'None' + try: + this, path, get_params, post_params, server = args # @UnusedVariable + part_id = post_params['disk'] + post_params['part'] + if this.locked.get(part_id, False): + this.locked[part_id] = True + fnc(*args, **kwargs) + else: + return 'partition locked' + except Exception as e: + this.locked[part_id] = False + return 'error {}'.format(e) + finally: + if sync is True: + this.locked[part_id] = False + logger.debug('Lock status: {} {}'.format(fnc, this.locked)) + + return wrapper + + return outer + + +class OpenGnSysWorker(ServerWorker): + name = 'opengnsys' + interface = None # Bound interface for OpenGnsys + REST = None # REST object + logged_in = False # User session flag + browser = {} # Browser info + commands = [] # Running commands + random = None # Random string for secure connections + length = 32 # Random string length + access_token = refresh_token = None # Server authorization tokens + grant_type = 'http://opengnsys.es/grants/og_client' + + def _launch_browser(self, url): + """ + Launchs the Browser with specified URL + :param url: URL to show + """ + logger.debug('Launching browser with URL: {}'.format(url)) + # Trying to kill an old browser + try: + os.kill(self.browser['process'].pid, signal.SIGKILL) + except OSError: + logger.warn('Cannot kill the old browser process') + except KeyError: + # There is no previous browser + pass + self.browser['url'] = url + self.browser['process'] = subprocess.Popen(['browser', '-qws', url]) + + def _task_command(self, route, code, op_id, send_config=False): + """ + Task to execute a command and return results to a server URI + :param route: server callback REST route to return results + :param code: code to execute + :param op_id: operation id. + """ + menu_url = '' + # Show execution tacking log, if OGAgent runs on ogLive + os_type = operations.os_type.lower() + if os_type == 'oglive': + menu_url = self.browser['url'] + self._launch_browser('http://localhost/cgi-bin/httpd-log.sh') + # Execute the code + (stat, out, err) = operations.exec_command(code) + # Remove command from the list + for c in self.commands: + if c.getName() == op_id: + self.commands.remove(c) + # Remove the REST API prefix, if needed + if route.startswith(self.REST.endpoint): + route = route[len(self.REST.endpoint):] + # Send back exit status and outputs (base64-encoded) + self.REST.sendMessage(route, {'mac': self.interface.mac, 'ip': self.interface.ip, 'trace': op_id, + 'status': stat, 'output': out.encode('base64'), 'error': err.encode('base64')}) + # Show latest menu, if OGAgent runs on ogLive + if os_type == 'oglive': + # Send configuration data, if needed + if send_config: + self.REST.sendMessage('clients/configs', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'config': operations.get_configuration()}) + self._launch_browser(menu_url) + + def onActivation(self): + """ + Sends OGAgent activation notification to OpenGnsys server + """ + t = 0 + # Generate random secret to send on activation + self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length)) + # Ensure cfg has required configuration variables or an exception will be thrown + url = self.service.config.get('opengnsys', 'remote') + server_client = self.service.config.get('opengnsys', 'client') + server_secret = self.service.config.get('opengnsys', 'secret') + if operations.os_type == 'ogLive' and 'oglive' in os.environ: + # Replacing server IP if its running on ogLive client + logger.debug('Activating on ogLive client, new server is {}'.format(os.environ['oglive'])) + url = parse.urlsplit(url)._replace(netloc=os.environ['oglive']).geturl() + if not url.endswith(os.path.sep): + url += os.path.sep + self.REST = REST(url) + # Get network interfaces until they are active or timeout (5 minutes) + for t in range(0, 300): + try: + self.interface = list(operations.getNetworkInfo())[0] # Get first network interface + except Exception as e: + # Wait 1 sec. and retry + time.sleep(1) + finally: + # Exit loop if interface is active + if self.interface: + if t > 0: + logger.debug("Fetch connection data after {} tries".format(t)) + break + # Raise error after timeout + if not self.interface: + raise e + # Compose login route + login_route = 'oauth/v2/token?client_id=' + server_client + '&client_secret=' + server_secret + \ + '&grant_type=' + self.grant_type + '&ip=' + self.interface.ip + '&mac=' + self.interface.mac + \ + '&token=' + self.random + # Send initialization login message + response = None + # Loop to send initialization message + for t in range(0, 100): + try: + try: + # New web compatibility. + self.REST = REST(self.service.config.get('opengnsys', 'remote')) + response = self.REST.sendMessage(login_route) + break + except: + # Trying to initialize on alternative server, if defined + # (used in "exam mode" from the University of Seville) + self.REST = REST(self.service.config.get('opengnsys', 'altremote')) + response = self.REST.sendMessage(login_route) + break + except: + time.sleep(3) + # Raise error after timeout or authentication failure + if 0 < t < 100: + logger.debug('Successful connection after {} tries'.format(t)) + elif t == 100: + raise Exception('Initialization error: Cannot connect to remote server') + if response['access_token'] is None: + raise Exception('Initialization error: Cannot obtain access token') + # Read access tokens + self.access_token = response['access_token'] + self.refresh_token = response['refresh_token'] + # Once authenticated with the server, change the API URL for private request + self.REST = REST(url + 'api/private') + # Set authorization tokens in the REST object, so in each request this token will be used + self.REST.set_authorization_headers(self.access_token, self.refresh_token) + # Completing OGAgent initialization process + os_type = operations.os_type.lower() + if os_type == 'oglive': + # Create HTML file (TEMPORARY) + message = """ + + + + +

+ OpenGnsys 3 +
+

+ + +""" + f = open('/tmp/init.html', 'w') + f.write(message) + f.close() + # Launching Browser + self._launch_browser('/tmp/init.html') + self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'status': 'initializing'}) + # Send configuration message + self.REST.sendMessage('clients/configs', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'config': operations.get_configuration()}) + # Launching new Browser with client's menu + # menu_url = self.REST.sendMessage('menus?mac' + self.interface.mac + '&ip=' + self.interface.ip) + menu_url = '/opt/opengnsys/log/' + self.interface.ip + '.info.html' # TEMPORARY menu + self._launch_browser(menu_url) + else: + # Delete marking files + for f in ['ogboot.me', 'ogboot.firstboot', 'ogboot.secondboot']: + try: + os.remove(os.sep + f) + except OSError: + pass + # Copy file "HostsFile.FirstOctetOfIPAddress" to "HostsFile", if it exists + # (used in "exam mode" from the University of Seville) + hosts_file = os.path.join(operations.get_etc_path(), 'hosts') + new_file = hosts_file + '.' + self.interface.ip.split('.')[0] + if os.path.isfile(new_file): + shutil.copy2(new_file, hosts_file) + # Return status message + self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'status': os_type}) + + def onDeactivation(self): + """ + Sends OGAgent stopping notification to OpenGnsys server + """ + logger.debug('onDeactivation') + self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'ostype': operations.os_type, 'osversion': operations.os_version, + 'status': 'off'}) + + def processClientMessage(self, message, data): + logger.debug('Got OpenGnsys message from client: {}, data {}'.format(message, data)) + + def onLogin(self, data): + """ + Sends session login notification to OpenGnsys server + """ + user, sep, language = data.partition(',') + logger.debug('Received login for {} with language {}'.format(user, language)) + self.logged_in = True + self.REST.sendMessage('ogagent/loggedin', {'ip': self.interface.ip, 'user': user, 'language': language, + 'ostype': operations.os_type, 'osversion': operations.os_version}) + + def onLogout(self, user): + """ + Sends session logout notification to OpenGnsys server + """ + logger.debug('Received logout for {}'.format(user)) + self.logged_in = False + self.REST.sendMessage('ogagent/loggedout', {'ip': self.interface.ip, 'user': user}) + + def process_ogclient(self, path, get_params, post_params, server): + """ + This method can be overridden to provide your own message processor, or better you can + implement a method that is called exactly as "process_" + path[0] (module name has been removed from path + array) and this default processMessage will invoke it + * Example: + Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z + The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this: + module.processMessage(["mazinger","Z"], get_params, post_params) + + This method will process "mazinger", and look for a "self" method that is called "process_mazinger", + and invoke it this way: + return self.process_mazinger(["Z"], get_params, post_params) + + In the case path is empty (that is, the path is composed only by the module name, like in + "http://example.com/Sample", the "process" method will be invoked directly + + The methods must return data that can be serialized to json (i.e. Objects are not serializable to json, + basic type are) + """ + if not path: + return "ok" + try: + operation = getattr(self, 'ogclient_' + path[0]) + except Exception: + raise Exception('Message processor for "{}" not found'.format(path[0])) + return operation(path[1:], get_params, post_params) + + def process_status(self, path, get_params, post_params, server): + """ + Returns client status (OS type or execution status) and login status + :param path: + :param get_params: + :param post_params: + :param server: + :return: JSON object {"status": "status_code", "loggedin": boolean} + """ + res = {'loggedin': self.logged_in} + try: + res['status'] = operations.os_type.lower() + except KeyError: + res['status'] = '' + # Check if OpenGnsys Client is busy + if res['status'] == 'oglive' and len(self.commands) > 0: + res['status'] = 'busy' + return res + + @check_secret + def process_reboot(self, path, get_params, post_params, server): + """ + Launches a system reboot operation + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} + """ + logger.debug('Received reboot operation') + + # Rebooting thread + def rebt(): + operations.reboot() + + threading.Thread(target=rebt).start() + return {'op': 'launched'} + + @check_secret + def process_poweroff(self, path, get_params, post_params, server): + """ + Launches a system power off operation + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} + """ + logger.debug('Received poweroff operation') + + # Powering off thread + def pwoff(): + time.sleep(2) + operations.poweroff() + + threading.Thread(target=pwoff).start() + return {'op': 'launched'} + + @check_secret + def process_script(self, path, get_params, post_params, server): + """ + Processes an script execution (script should be encoded in base64) + :param path: + :param get_params: + :param post_params: JSON object {"redirect_uri, "uri", "script": "commands", "id": trace_id} + :param server: authorization header + :return: JSON object {"op": "launched"} or {"error": "message"} + """ + logger.debug('Processing script request') + # Processing data + try: + script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8') + op_id = post_params.get('id') + route = post_params.get('redirectUri') + send_config = (post_params.get('sendConfig', 'false') == 'true') + # Check if the thread id. exists + for c in self.commands: + if c.getName() == str(op_id): + raise Exception('Task id. already exists: {}'.format(op_id)) + if post_params.get('client', 'false') == 'false': + # Launching a new thread + thr = threading.Thread(name=op_id, target=self._task_command, args=(route, script, op_id, send_config)) + thr.start() + self.commands.append(thr) + else: + # Executing as normal user + self.sendClientMessage('script', {'code': script}) + except Exception as e: + logger.error('Got exception {}'.format(e)) + return {'error': e} + return {'op': 'launched'} + + @check_secret + def process_logoff(self, path, get_params, post_params, server): + """ + Closes user session + """ + logger.debug('Received logoff operation') + # Send log off message to OGAgent client + self.sendClientMessage('logoff', {}) + return {'op': 'sent to client'} + + @check_secret + def process_popup(self, path, get_params, post_params, server): + """ + Shows a message popup on the user's session + """ + logger.debug('Received message operation') + # Send popup message to OGAgent client + self.sendClientMessage('popup', post_params) + return {'op': 'launched'} + + def process_client_popup(self, params): + self.REST.sendMessage('popup_done', params) + + @check_secret + def process_config(self, path, get_params, post_params, server): + """ + Returns client configuration + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object + """ + serialno = '' # Serial number + storage = [] # Storage configuration + warnings = 0 # Number of warnings + logger.debug('Received getconfig operation') + # Processing data + for row in operations.get_configuration().split(';'): + cols = row.split(':') + if len(cols) == 1: + if cols[0] != '': + # Serial number + serialno = cols[0] + else: + # Skip blank rows + pass + elif len(cols) == 7: + disk, npart, tpart, fs, opsys, size, usage = cols + try: + if int(npart) == 0: + # Disk information + storage.append({'disk': int(disk), 'parttable': int(tpart), 'size': int(size)}) + else: + # Partition information + storage.append({'disk': int(disk), 'partition': int(npart), 'parttype': tpart, + 'filesystem': fs, 'operatingsystem': opsys, 'size': int(size), + 'usage': int(usage)}) + except ValueError: + logger.warn('Configuration parameter error: {}'.format(cols)) + warnings += 1 + else: + # Log warnings + logger.warn('Configuration data error: {}'.format(cols)) + warnings += 1 + # Return configuration data and count of warnings + return {'serialno': serialno, 'storage': storage, 'warnings': warnings} + + @check_secret + def process_execinfo(self, path, get_params, post_params, server): + """ + Returns running commands information + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON array: [["callback_url", "commands", trace_id], ...] + """ + data = [] + logger.debug('Received execinfo operation') + # Return the arguments of all running threads + for c in self.commands: + if c.is_alive(): + data.append(c.__dict__['_Thread__args']) + return data + + @check_secret + def process_stopcmd(self, path, get_params, post_params, server): + """ + Stops a running process identified by its trace id. + :param path: + :param get_params: + :param post_params: JSON object {"trace": trace_id} + :param server: authorization header + :return: JSON object: {"stopped": trace_id} + """ + logger.debug('Received stopcmd operation with params {}:'.format(post_params)) + # Find operation id. and stop the thread + op_id = post_params.get('trace') + for c in self.commands: + if c.is_alive() and c.getName() == str(op_id): + c._Thread__stop() + return {"stopped": op_id} + return {} diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/server/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/modules/server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/__init__.py new file mode 100644 index 0000000..3a98c78 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/daemon.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/daemon.py new file mode 100644 index 0000000..3753808 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/daemon.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: : http://www.jejik.com/authors/sander_marechal/ +@see: : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ +''' + +from __future__ import unicode_literals +import sys +import os +import time +import atexit +from opengnsys.log import logger + +from signal import SIGTERM + + +class Daemon: + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError as e: + logger.error("fork #1 error: {}".format(e)) + sys.stderr.write("fork #1 failed: {}\n".format(e)) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError as e: + logger.error("fork #2 error: {}".format(e)) + sys.stderr.write("fork #2 failed: {}\n".format(e)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = open(self.stdin, 'r') + so = open(self.stdout, 'a+') + se = open(self.stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + with open(self.pidfile, 'w+') as f: + f.write("{}\n".format(pid)) + + def delpid(self): + try: + os.remove(self.pidfile) + except Exception: + # Not found/not permissions or whatever... + pass + + def start(self): + """ + Start the daemon + """ + logger.debug('Starting daemon') + # Check for a pidfile to see if the daemon already runs + try: + pf = open(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile {} already exist. Daemon already running?\n".format(pid) + logger.error(message) + sys.stderr.write(message) + sys.exit(1) + + # Start the daemon + self.daemonize() + try: + self.run() + except Exception as e: + logger.error('Exception running process: {}'.format(e)) + + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = open(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid is None: + message = "pidfile {} does not exist. Daemon not running?\n".format(self.pidfile) + logger.info(message) + # sys.stderr.write(message) + return # not an error in a restart + + # Try killing the daemon process + try: + for i in range(10): + os.kill(pid, SIGTERM) + time.sleep(1) + except OSError as err: + if err.errno == 3: # No such process + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + sys.stderr.write(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + # Overridables + def run(self): + """ + You should override this method when you subclass Daemon. It will be called after the process has been + daemonized by start() or restart(). + """ diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/operations.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/operations.py new file mode 100644 index 0000000..8c74f74 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/oglive/operations.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +@author: Ramón M. Gómez, ramongomez at us dot es +""" +from __future__ import unicode_literals + +import socket +import platform +import os +import fcntl +import subprocess +import struct +import array +import six +import chardet +from opengnsys import utils +from opengnsys.log import logger + + +def _getMacAddr(ifname): + """ + Returns the mac address of an interface + Mac is returned as unicode utf-8 encoded + """ + if isinstance(ifname, list): + return dict([(name, _getMacAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifname[:15]))) + return six.text_type(''.join(['%02x:' % char for char in info[18:24]])[:-1]) + except Exception: + return None + + +def _getIpAddr(ifname): + """ + Returns the ip address of an interface + Ip is returned as unicode utf-8 encoded + """ + if isinstance(ifname, list): + return dict([(name, _getIpAddr(name)) for name in ifname]) + if isinstance(ifname, six.text_type): + ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + return six.text_type(socket.inet_ntoa(fcntl.ioctl( + s.fileno(), + 0x8915, # SIOCGIFADDR + struct.pack(str('256s'), ifname[:15]) + )[20:24])) + except Exception: + return None + + +def _getInterfaces(): + """ + Returns a list of interfaces names coded in utf-8 + """ + max_possible = 128 # arbitrary. raise if needed. + space = max_possible * 16 + if platform.architecture()[0] == '32bit': + offset, length = 32, 32 + elif platform.architecture()[0] == '64bit': + offset, length = 16, 40 + else: + raise OSError('Unknown arquitecture {0}'.format(platform.architecture()[0])) + + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + names = array.array(str('B'), b'\0' * space) + outbytes = struct.unpack(str('iL'), fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack(str('iL'), space, names.buffer_info()[0]) + ))[0] + namestr = names.tostring() + # return namestr, outbytes + return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)] + + +def _getIpAndMac(ifname): + ip, mac = _getIpAddr(ifname), _getMacAddr(ifname) + return ip, mac + + +def _exec_ogcommand(ogcmd): + """ + Loads OpenGnsys environment variables, executes the command and returns the result + """ + ret = subprocess.check_output(ogcmd, shell=True) + return ret + + +def getComputerName(): + """ + Returns computer name, with no domain + """ + return socket.gethostname().split('.')[0] + + +def getNetworkInfo(): + """ + Obtains a list of network interfaces + :return: A "generator" of elements, that are dict-as-object, with this elements: + name: Name of the interface + mac: mac of the interface + ip: ip of the interface + """ + for ifname in _getInterfaces(): + ip, mac = _getIpAndMac(ifname) + if mac != '00:00:00:00:00:00': # Skips local interfaces + yield utils.Bunch(name=ifname, mac=mac, ip=ip) + + +def getDomainName(): + return '' + + +def get_oglive_version(): + """ + Returns ogLive Kernel version and architecture + :return: kernel version + """ + kv = platform.os.uname() + return kv[2] + ', ' + kv[4] + + +def reboot(): + """ + Simple reboot using OpenGnsys script + """ + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + _exec_ogcommand('/opt/opengnsys/scripts/reboot') + + +def poweroff(): + """ + Simple power off using OpenGnsys script + """ + # Workaround for dummy thread + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + _exec_ogcommand('/opt/opengnsys/scripts/poweroff') + + +def get_etc_path(): + """ + Returns etc directory path. + """ + return os.sep + 'etc' + + +def get_configuration(): + """ + Returns client's configuration + Warning: this operation may take some time + :return: + """ + try: + _exec_ogcommand('/opt/opengnsys/interfaceAdm/getConfiguration') + # Returns content of configuration file + cfgdata = open('/tmp/getconfig', 'r').read().strip() + except IOError: + cfgdata = '' + return cfgdata + + +def exec_command(cmd): + """ + Executing a shell command + :param cmd: + :return: object with components: + output: standard output + error: error output + exit: exit code + """ + proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = proc.communicate() + try: + if out is not None: + encoding = chardet.detect(out)["encoding"] + if encoding is not None: + out = out.decode(encoding).encode("utf8") + if err is not None: + encoding = chardet.detect(err)["encoding"] + if encoding is not None: + err = err.decode(encoding).encode("utf8") + except Exception as e: + logger.debug("ERROR EXEC COMMAND: {}".format(str(e))) + + stat = proc.returncode + return stat, out, err + + +def get_hardware(): + """ + Returns client's hardware list + :return: + """ + try: + filepath = _exec_ogcommand('/opt/opengnsys/scripts/listHardwareInfo').strip() + # Returns content of configuration file, skipping the header line and newline characters + with open(filepath, 'r') as f: + harddata = map(str.strip, f.readlines()[1:]) + except IOError: + harddata = '' + return harddata + + +def get_software(disk, part): + """ + Returns software list installed on an operating system + :param disk: + :param part: + :return: + """ + try: + filepath = _exec_ogcommand('/opt/opengnsys/scripts/listSoftwareInfo {} {}'.format(disk, part)).strip() + # Returns content of configuration file, skipping the header line and newline characters + with open(filepath, 'r') as f: + softdata = map(str.strip, f.readlines()) + except IOError: + softdata = '' + return softdata diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/operations.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/operations.py new file mode 100644 index 0000000..a81d0c0 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/operations.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +@author: Ramón M. Gómez, ramongomez at us dot es +""" +# pylint: disable=unused-wildcard-import,wildcard-import + +from __future__ import unicode_literals + +import sys +import os + +# Importing platform operations and getting operating system data. +if sys.platform == 'win32': + from .windows.operations import * # @UnusedWildImport + os_type = 'Windows' + os_version = getWindowsVersion() +else: + if sys.platform == 'darwin': + from .macos.operations import * # @UnusedWildImport + os_type = 'MacOS' + os_version = getMacosVersion().replace(',', '') + else: + if os.path.exists('/scripts/oginit'): + from .oglive.operations import * # @UnusedWildImport + os_type = 'ogLive' + os_version = get_oglive_version().replace(',', '') + else: + from .linux.operations import * # @UnusedWildImport + os_type = 'Linux' + os_version = getLinuxVersion().replace(',', '') diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/scriptThread.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/scriptThread.py new file mode 100644 index 0000000..2a6779b --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/scriptThread.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 201 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' + +# pylint: disable-msg=E1101,W0703 + +from opengnsys.log import logger + +import threading +import six + + +class ScriptExecutorThread(threading.Thread): + def __init__(self, script): + super(ScriptExecutorThread, self).__init__() + self.script = script + + def run(self): + try: + logger.debug('Executing script: {}'.format(self.script)) + six.exec_(self.script, globals(), None) + except Exception as e: + logger.error('Error executing script: {}'.format(e)) diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/service.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/service.py new file mode 100644 index 0000000..4a44028 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/service.py @@ -0,0 +1,249 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +from .log import logger +from .config import readConfig +from .utils import exceptionToMessage + +from . import ipc +from . import httpserver +from .loader import loadModules + +import socket +import time +import json +import six + +IPC_PORT = 10398 + + +class CommonService(object): + isAlive = True + ipc = None + httpServer = None + modules = None + + def __init__(self): + logger.info('----------------------------------------') + logger.info('Initializing OpenGnsys Agent') + + # Read configuration file before proceding & ensures minimal config is there + + self.config = readConfig() + + # Get opengnsys section as dict + cfg = dict(self.config.items('opengnsys')) + + # Set up log level + logger.setLevel(cfg.get('log', 'INFO')) + + + logger.debug('Loaded configuration from opengnsys.cfg:') + for section in self.config.sections(): + logger.debug('Section {} = {}'.format(section, self.config.items(section))) + + + if logger.logger.isWindows(): + # Logs will also go to windows event log for services + logger.logger.serviceLogger = True + + self.address = (cfg.get('address', '0.0.0.0'), int(cfg.get('port', '10997'))) + self.ipcport = int(cfg.get('ipc_port', IPC_PORT)) + + self.timeout = int(cfg.get('timeout', '20')) + + logger.debug('Socket timeout: {}'.format(self.timeout)) + socket.setdefaulttimeout(self.timeout) + + # Now load modules + self.modules = loadModules(self) + logger.debug('Modules: {}'.format(list(v.name for v in self.modules))) + + def stop(self): + ''' + Requests service termination + ''' + self.isAlive = False + + # ******************************** + # * Internal messages processors * + # ******************************** + def notifyLogin(self, username): + for v in self.modules: + try: + logger.debug('Notifying login of user {} to module {}'.format(username, v.name)) + v.onLogin(username) + except Exception as e: + logger.error('Got exception {} processing login message on {}'.format(e, v.name)) + + def notifyLogout(self, username): + for v in self.modules: + try: + logger.debug('Notifying logout of user {} to module {}'.format(username, v.name)) + v.onLogout(username) + except Exception as e: + logger.error('Got exception {} processing logout message on {}'.format(e, v.name)) + + def notifyMessage(self, data): + module, message, data = data.split('\0') + for v in self.modules: + if v.name == module: # Case Sensitive!!!! + try: + logger.debug('Notifying message {} to module {} with json data {}'.format(message, v.name, data)) + v.processClientMessage(message, json.loads(data)) + return + except Exception as e: + logger.error('Got exception {} processing generic message on {}'.format(e, v.name)) + + logger.error('Module {} not found, messsage {} not sent'.format(module, message)) + + + def clientMessageProcessor(self, msg, data): + ''' + Callback, invoked from IPC, on its own thread (not the main thread). + This thread will "block" communication with agent untill finished, but this should be no problem + ''' + logger.debug('Got message {}'.format(msg)) + + if msg == ipc.REQ_LOGIN: + self.notifyLogin(data) + elif msg == ipc.REQ_LOGOUT: + self.notifyLogout(data) + elif msg == ipc.REQ_MESSAGE: + self.notifyMessage(data) + + def initialize(self): + # ****************************************** + # * Initialize listeners, modules, etc... + # ****************************************** + + if six.PY3 is False: + import threading + threading._DummyThread._Thread__stop = lambda x: 42 + + logger.debug('Starting IPC listener at {}'.format(IPC_PORT)) + self.ipc = ipc.ServerIPC(self.ipcport, clientMessageProcessor=self.clientMessageProcessor) + self.ipc.start() + + # And http threaded server + self.httpServer = httpserver.HTTPServerThread(self.address, self) + self.httpServer.start() + + # And lastly invoke modules activation + validMods = [] + for mod in self.modules: + try: + logger.debug('Activating module {}'.format(mod.name)) + mod.activate() + validMods.append(mod) + except Exception as e: + logger.exception() + logger.error("Activation of {} failed: {}".format(mod.name, exceptionToMessage(e))) + + self.modules[:] = validMods # copy instead of assignment + + logger.debug('Modules after activation: {}'.format(list(v.name for v in self.modules))) + + def terminate(self): + # First invoke deactivate on modules + for mod in reversed(self.modules): + try: + logger.debug('Deactivating module {}'.format(mod.name)) + mod.deactivate() + except Exception as e: + logger.exception() + logger.error("Deactivation of {} failed: {}".format(mod.name, exceptionToMessage(e))) + + # Remove IPC threads + if self.ipc is not None: + try: + self.ipc.stop() + except Exception: + logger.error('Couln\'t stop ipc server') + + if self.httpServer is not None: + try: + self.httpServer.stop() + except Exception: + logger.error('Couln\'t stop RESTApi server') + + self.notifyStop() + + # **************************************** + # Methods that CAN BE overridden by agents + # **************************************** + def doWait(self, miliseconds): + ''' + Invoked to wait a bit + CAN be OVERRIDDEN + ''' + time.sleep(float(miliseconds) / 1000) + + def notifyStop(self): + ''' + Overridden to log stop + ''' + logger.info('Service is being stopped') + + # *************************************************** + # * Helpers, convenient methods to facilitate comms * + # *************************************************** + def sendClientMessage(self, toModule, message, data): + ''' + Sends a message to the clients using IPC + The data is converted to json, so ensure that it is serializable. + All IPC is asynchronous, so if you expect a response, this will be sent by client using another message + + @param toModule: Module that will receive this message + @param message: Message to send + @param data: data to send + ''' + self.ipc.sendMessageMessage('\0'.join((toModule, message, json.dumps(data)))) + + def sendScriptMessage(self, script): + ''' + Sends an script to be executed by client + ''' + self.ipc.sendScriptMessage(script) + + def sendLogoffMessage(self): + ''' + Sends a logoff message to client + ''' + self.ipc.sendLoggofMessage() + + def sendPopupMessage(self, title, message): + ''' + Sends a poup box to be displayed by client + ''' + self.ipc.sendPopupMessage(title, message) diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/utils.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/utils.py new file mode 100644 index 0000000..9480a6a --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/utils.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import sys +import six + +if sys.platform == 'win32': + _fromEncoding = 'windows-1250' +else: + _fromEncoding = 'utf-8' + + +def toUnicode(msg): + try: + if not isinstance(msg, six.text_type): + if isinstance(msg, six.binary_type): + return msg.decode(_fromEncoding, 'ignore') + return six.text_type(msg) + else: + return msg + except Exception: + try: + return six.text_type(msg) + except Exception: + return '' + + +def exceptionToMessage(e): + msg = '' + for arg in e.args: + if isinstance(arg, Exception): + msg = msg + exceptionToMessage(arg) + else: + msg = msg + toUnicode(arg) + '. ' + return msg + + +class Bunch(dict): + def __init__(self, **kw): + dict.__init__(self, kw) + self.__dict__ = self + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/OGAgentService.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/OGAgentService.py new file mode 100644 index 0000000..71716d7 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/OGAgentService.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals +# pylint: disable=unused-wildcard-import, wildcard-import + +import win32serviceutil # @UnresolvedImport, pylint: disable=import-error +import win32service # @UnresolvedImport, pylint: disable=import-error +import win32security # @UnresolvedImport, pylint: disable=import-error +import win32net # @UnresolvedImport, pylint: disable=import-error +import win32event # @UnresolvedImport, pylint: disable=import-error +import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error +import pythoncom # @UnresolvedImport, pylint: disable=import-error +import servicemanager # @UnresolvedImport, pylint: disable=import-error +import os + +from opengnsys import operations +from opengnsys.service import CommonService + +from opengnsys.log import logger + +class OGAgentSvc(win32serviceutil.ServiceFramework, CommonService): + ''' + This class represents a Windows Service for managing Agent interactions + with OpenGnsys Server + ''' + _svc_name_ = "OGAgent" + _svc_display_name_ = "OpenGnsys Agent Service" + _svc_description_ = "OpenGnsys Agent for Operating Systems" + # 'System Event Notification' is the SENS service + _svc_deps_ = ['EventLog'] + + def __init__(self, args): + win32serviceutil.ServiceFramework.__init__(self, args) + CommonService.__init__(self) + self.hWaitStop = win32event.CreateEvent(None, 1, 0, None) + self._user = None + + def SvcStop(self): + self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) + self.isAlive = False + win32event.SetEvent(self.hWaitStop) + + SvcShutdown = SvcStop + + def notifyStop(self): + servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, + servicemanager.PYS_SERVICE_STOPPED, + (self._svc_name_, '')) + + def doWait(self, miliseconds): + win32event.WaitForSingleObject(self.hWaitStop, miliseconds) + + def SvcDoRun(self): + ''' + Main service loop + ''' + try: + logger.debug('running SvcDoRun') + servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, + servicemanager.PYS_SERVICE_STARTED, + (self._svc_name_, '')) + + # call the CoInitialize to allow the registration to run in an other + # thread + logger.debug('Initializing com...') + pythoncom.CoInitialize() + + # Initialize remaining service data + self.initialize() + except Exception: # Any init exception wil be caught, service must be then restarted + logger.exception() + logger.debug('Exiting service with failure status') + os._exit(-1) # pylint: disable=protected-access + + # ********************* + # * Main Service loop * + # ********************* + try: + while self.isAlive: + # Pumps & processes any waiting messages + pythoncom.PumpWaitingMessages() + win32event.WaitForSingleObject(self.hWaitStop, 1000) + except Exception as e: + logger.error('Caught exception on main loop: {}'.format(e)) + + logger.debug('Exited main loop, deregistering SENS') + + self.terminate() # Ends IPC servers + + self.notifyStop() + + +if __name__ == '__main__': + + win32serviceutil.HandleCommandLine(OGAgentSvc) diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/__init__.py new file mode 100644 index 0000000..e662942 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/__init__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import os +import sys + +# Change to application directory. +os.chdir(os.path.dirname(sys.argv[0])) + diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/log.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/log.py new file mode 100644 index 0000000..745fd03 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/log.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import servicemanager # @UnresolvedImport, pylint: disable=import-error +import logging +import os +import tempfile + +# Valid logging levels, from UDS Broker (uds.core.utils.log) +OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in range(6)) + + +class LocalLogger(object): + def __init__(self): + # tempdir is different for "user application" and "service" + # service wil get c:\windows\temp, while user will get c:\users\XXX\temp + logging.basicConfig( + filename=os.path.join(tempfile.gettempdir(), 'opengnsys.log'), + filemode='a', + format='%(levelname)s %(asctime)s %(message)s', + level=logging.DEBUG + ) + self.logger = logging.getLogger('opengnsys') + self.serviceLogger = False + + def log(self, level, message): + # Debug messages are logged to a file + # our loglevels are 10000 (other), 20000 (debug), .... + # logging levels are 10 (debug), 20 (info) + # OTHER = logging.NOTSET + self.logger.log(level / 1000 - 10, message) + + if level < INFO or self.serviceLogger is False: # Only information and above will be on event log + return + + if level < WARN: # Info + servicemanager.LogInfoMsg(message) + elif level < ERROR: # WARN + servicemanager.LogWarningMsg(message) + else: # Error & Fatal + servicemanager.LogErrorMsg(message) + + def isWindows(self): + return True + + def isLinux(self): + return False diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/operations.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/operations.py new file mode 100644 index 0000000..95331fd --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/windows/operations.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import os +import locale +import subprocess +import ctypes +from ctypes.wintypes import DWORD, LPCWSTR +import win32com.client # @UnresolvedImport, pylint: disable=import-error +import win32net # @UnresolvedImport, pylint: disable=import-error +import win32security # @UnresolvedImport, pylint: disable=import-error +import win32api # @UnresolvedImport, pylint: disable=import-error +import win32con # @UnresolvedImport, pylint: disable=import-error + +from opengnsys import utils +from opengnsys.log import logger + + +def getErrorMessage(res=0): + msg = win32api.FormatMessage(res) + return msg.decode('windows-1250', 'ignore') + + +def getComputerName(): + return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname) + + +def getNetworkInfo(): + ''' + Obtains a list of network interfaces + @return: A "generator" of elements, that are dict-as-object, with this elements: + name: Name of the interface + mac: mac of the interface + ip: ip of the interface + ''' + obj = win32com.client.Dispatch("WbemScripting.SWbemLocator") + wmobj = obj.ConnectServer("localhost", "root\cimv2") + adapters = wmobj.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True") + try: + for obj in adapters: + if obj.DefaultIPGateway is None: # Skip adapters without default router + continue + for ip in obj.IPAddress: + if ':' in ip: # Is IPV6, skip this + continue + if ip is None or ip == '' or ip.startswith('169.254') or ip.startswith('0.'): # If single link ip, or no ip + continue + logger.debug('Net config found: {}=({}, {})'.format(obj.Caption, obj.MACAddress, ip)) + yield utils.Bunch(name=obj.Caption, mac=obj.MACAddress, ip=ip) + except Exception: + return + + +def getDomainName(): + ''' + Will return the domain name if we belong a domain, else None + (if part of a network group, will also return None) + ''' + # Status: + # 0 = Unknown + # 1 = Unjoined + # 2 = Workgroup + # 3 = Domain + domain, status = win32net.NetGetJoinInformation() + if status != 3: + domain = None + + return domain + + +def getWindowsVersion(): + ''' + Returns Windows version. + ''' + import _winreg + reg = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion') + try: + data = '{} {}'.format(_winreg.QueryValueEx(reg, 'ProductName')[0], _winreg.QueryValueEx(reg, 'ReleaseId')[0]) + except Exception: + data = '{} {}'.format(_winreg.QueryValueEx(reg, 'ProductName')[0], _winreg.QueryValueEx(reg, 'CurrentBuildNumber')[0]) + reg.Close() + return data + + +EWX_LOGOFF = 0x00000000 +EWX_SHUTDOWN = 0x00000001 +EWX_REBOOT = 0x00000002 +EWX_FORCE = 0x00000004 +EWX_POWEROFF = 0x00000008 +EWX_FORCEIFHUNG = 0x00000010 + + +def reboot(flags=EWX_FORCEIFHUNG | EWX_REBOOT): + hproc = win32api.GetCurrentProcess() + htok = win32security.OpenProcessToken(hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY) + privs = ((win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), win32security.SE_PRIVILEGE_ENABLED),) + win32security.AdjustTokenPrivileges(htok, 0, privs) + win32api.ExitWindowsEx(flags, 0) + +def poweroff(flags=0): + ''' + Simple poweroff command. + ''' + reboot(flags=EWX_FORCEIFHUNG | EWX_SHUTDOWN) + +def logoff(): + win32api.ExitWindowsEx(EWX_LOGOFF) + + +def renameComputer(newName): + # Needs admin privileges to work + if ctypes.windll.kernel32.SetComputerNameExW(DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)) == 0: # @UndefinedVariable + # win32api.FormatMessage -> returns error string + # win32api.GetLastError -> returns error code + # (just put this comment here to remember to log this when logger is available) + error = getErrorMessage() + computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname) + raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error)) + + +NETSETUP_JOIN_DOMAIN = 0x00000001 +NETSETUP_ACCT_CREATE = 0x00000002 +NETSETUP_ACCT_DELETE = 0x00000004 +NETSETUP_WIN9X_UPGRADE = 0x00000010 +NETSETUP_DOMAIN_JOIN_IF_JOINED = 0x00000020 +NETSETUP_JOIN_UNSECURE = 0x00000040 +NETSETUP_MACHINE_PWD_PASSED = 0x00000080 +NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400 +NETSETUP_DEFER_SPN_SET = 0x1000000 + + +def joinDomain(domain, ou, account, password, executeInOneStep=False): + ''' + Joins machine to a windows domain + :param domain: Domain to join to + :param ou: Ou that will hold machine + :param account: Account used to join domain + :param password: Password of account used to join domain + :param executeInOneStep: If true, means that this machine has been renamed and wants to add NETSETUP_JOIN_WITH_NEW_NAME to request so we can do rename/join in one step. + ''' + # If account do not have domain, include it + if '@' not in account and '\\' not in account: + if '.' in domain: + account = account + '@' + domain + else: + account = domain + '\\' + account + + # Do log + flags = NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN + + if executeInOneStep: + flags |= NETSETUP_JOIN_WITH_NEW_NAME + + flags = DWORD(flags) + + domain = LPCWSTR(domain) + + # Must be in format "ou=.., ..., dc=...," + ou = LPCWSTR(ou) if ou is not None and ou != '' else None + account = LPCWSTR(account) + password = LPCWSTR(password) + + res = ctypes.windll.netapi32.NetJoinDomain(None, domain, ou, account, password, flags) + # Machine found in another ou, use it and warn this on log + if res == 2224: + flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN) + res = ctypes.windll.netapi32.NetJoinDomain(None, domain, None, account, password, flags) + if res != 0: + # Log the error + error = getErrorMessage(res) + if res == 1355: + error = "DC Is not reachable" + print('{} {}'.format(res, error)) + raise Exception('Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(domain.value, account.value, ', under OU {}'.format(ou.value) if ou.value is not None else '', res, error)) + + +def changeUserPassword(user, oldPassword, newPassword): + computerName = LPCWSTR(getComputerName()) + user = LPCWSTR(user) + oldPassword = LPCWSTR(oldPassword) + newPassword = LPCWSTR(newPassword) + + res = ctypes.windll.netapi32.NetUserChangePassword(computerName, user, oldPassword, newPassword) + + if res != 0: + # Log the error, and raise exception to parent + error = getErrorMessage() + raise Exception('Error changing password for user {}: {}'.format(user.value, error)) + + +class LASTINPUTINFO(ctypes.Structure): + _fields_ = [ + ('cbSize', ctypes.c_uint), + ('dwTime', ctypes.c_uint), + ] + + +def initIdleDuration(atLeastSeconds): + ''' + In windows, there is no need to set screensaver + ''' + pass + + +def getIdleDuration(): + lastInputInfo = LASTINPUTINFO() + lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo) + ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) + millis = ctypes.windll.kernel32.GetTickCount() - lastInputInfo.dwTime # @UndefinedVariable + return millis / 1000.0 + + +def getCurrentUser(): + ''' + Returns current logged in username + ''' + return os.environ['USERNAME'] + + +def getSessionLanguage(): + ''' + Returns the user's session language + ''' + return locale.getdefaultlocale()[0] + + +def showPopup(title, message): + ''' + Displays a message box on user's session (during 1 min). + ''' + return subprocess.call('mshta "javascript:var sh=new ActiveXObject(\'WScript.Shell\'); sh.Popup( \'{}\', 60, \'{}\', 64); close()"'.format(message.encode('unicode_escape'), title.encode('unicode_escape')), shell=True) + + +def get_etc_path(): + """ + :return: + Returns etc directory path. + """ + return os.path.join('C:', os.sep, 'Windows', 'System32', 'drivers', 'etc') diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/__init__.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/__init__.py new file mode 100644 index 0000000..f2bcd7d --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/__init__.py @@ -0,0 +1,2 @@ +from .server_worker import ServerWorker +from .client_worker import ClientWorker diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/client_worker.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/client_worker.py new file mode 100644 index 0000000..6a08380 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/client_worker.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +# pylint: disable=unused-wildcard-import,wildcard-import +from __future__ import unicode_literals + +class ClientWorker(object): + ''' + A ServerWorker is a server module that "works" for service + Most method are invoked inside their own thread, except onActivation & onDeactivation. + This two methods are invoked inside main service thread, take that into account when creating them + + * You must provide a module name (override name on your class), so we can identify the module by a "valid" name. + A valid name is like a valid python variable (do not use spaces, etc...) + * The name of the module is used as REST message destination id: + https://sampleserver:8888/[name]/.... + Remember that module names and REST path are case sensitive!!! + + ''' + name = None + service = None + + def __init__(self, service): + self.service = service + + def activate(self): + ''' + Convenient method to wrap onActivation, so we can include easyly custom common logic for activation in a future + ''' + self.onActivation() + + def deactivate(self): + ''' + Convenient method to wrap onActivation, so we can include easyly custom common logic for deactivation in a future + ''' + self.onDeactivation() + + def processMessage(self, message, params): + ''' + This method can be overriden to provide your own message proccessor, or better you can + implement a method that is called "process_" + message and this default processMessage will invoke it + * Example: + We got a message from OGAgent "Mazinger", with json params + module.processMessage("mazinger", jsonParams) + + This method will process "mazinguer", and look for a "self" method that is called "process_mazinger", and invoke it this way: + return self.process_mazinger(jsonParams) + + The methods must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are) + ''' + try: + operation = getattr(self, 'process_' + message) + except Exception: + raise Exception('Message processor for "{}" not found'.format(message)) + + return operation(params) + + def onActivation(self): + ''' + Invoked by Service for activation. + This MUST be overridden by modules! + This method is invoked inside main thread, so if it "hangs", complete service will hang + This should be no problem, but be advised about this + ''' + pass + + def onDeactivation(self): + ''' + Invoked by Service before unloading service + This MUST be overridden by modules! + This method is invoked inside main thread, so if it "hangs", complete service will hang + This should be no problem, but be advised about this + ''' + pass + + # ************************************* + # * Helper, convenient helper methods * + # ************************************* + def sendServerMessage(self, message, data): + ''' + Sends a message to connected ipc clients + By convenience, it uses the "current" moduel name as destination module name also. + If you need to send a message to a different module, you can use self.service.sendClientMessage(module, message, data) instead + og this helmer + ''' + self.service.ipc.sendMessage(self.name, message, data) + \ No newline at end of file diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/server_worker.py b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/server_worker.py new file mode 100644 index 0000000..141d657 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/OGAgent/opengnsys/workers/server_worker.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +# pylint: disable=unused-wildcard-import,wildcard-import +from __future__ import unicode_literals + +class ServerWorker(object): + ''' + A ServerWorker is a server module that "works" for service + Most method are invoked inside their own thread, except onActivation & onDeactivation. + This two methods are invoked inside main service thread, take that into account when creating them + + * You must provide a module name (override name on your class), so we can identify the module by a "valid" name. + A valid name is like a valid python variable (do not use spaces, etc...) + * The name of the module is used as REST message destination id: + https://sampleserver:8888/[name]/.... + Remember that module names and REST path are case sensitive!!! + + ''' + name = None + service = None + locked = False + + def __init__(self, service): + self.service = service + + def activate(self): + ''' + Convenient method to wrap onActivation, so we can include easyly custom common logic for activation in a future + ''' + self.onActivation() + + def deactivate(self): + ''' + Convenient method to wrap onActivation, so we can include easyly custom common logic for deactivation in a future + ''' + self.onDeactivation() + + def process(self, getParams, postParams, server): + ''' + This method is invoked on a message received with an empty path (that means a message with only the module name, like in "http://example.com/Sample" + Override it if you expect messages with that pattern + + Overriden method must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are) + ''' + raise NotImplementedError('Generic message processor is not supported') + + def processServerMessage(self, path, getParams, postParams, server): + ''' + This method can be overriden to provide your own message proccessor, or better you can + implement a method that is called exactly as "process_" + path[0] (module name has been removed from path array) and this default processMessage will invoke it + * Example: + Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z + The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this: + module.processMessage(["mazinger","Z"], getParams, postParams) + + This method will process "mazinguer", and look for a "self" method that is called "process_mazinger", and invoke it this way: + return self.process_mazinger(["Z"], getParams, postParams) + + In the case path is empty (that is, the path is composed only by the module name, like in "http://example.com/Sample", the "process" method + will be invoked directly + + The methods must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are) + ''' + if self.locked is True: + raise Exception('system is busy') + + if len(path) == 0: + return self.process(getParams, postParams, server) + try: + operation = getattr(self, 'process_' + path[0]) + except Exception: + raise Exception('Message processor for "{}" not found'.format(path[0])) + + return operation(path[1:], getParams, postParams, server) + + + def processClientMessage(self, message, data): + ''' + Invoked by Service when a client message is received (A message from user space Agent) + + This method can be overriden to provide your own message proccessor, or better you can + implement a method that is called exactly "process_client_" + message (module name has been removed from path) and this default processMessage will invoke it + * Example: + We got a message from OGAgent "Mazinger", with json params + module.processClientMessage("mazinger", jsonParams) + + This method will process "mazinguer", and look for a "self" method that is called "process_client_mazinger", and invoke it this way: + self.process_client_mazinger(jsonParams) + + The methods returns nothing (client communications are done asynchronously) + ''' + try: + operation = getattr(self, 'process_client_' + message) + except Exception: + raise Exception('Message processor for "{}" not found'.format(message)) + + operation(data) + + # raise NotImplementedError('Got a client message but no proccessor is implemented') + + + def onActivation(self): + ''' + Invoked by Service for activation. + This MUST be overridden by modules! + This method is invoked inside main thread, so if it "hangs", complete service will hang + This should be no problem, but be advised about this + ''' + pass + + def onDeactivation(self): + ''' + Invoked by Service before unloading service + This MUST be overridden by modules! + This method is invoked inside main thread, so if it "hangs", complete service will hang + This should be no problem, but be advised about this + ''' + pass + + + def onLogin(self, user): + ''' + Invoked by Service when an user login is detected + This CAN be overridden by modules + This method is invoked whenever the client (user space agent) notifies the server (Service) that a user has logged in. + This method is run on its own thread + ''' + pass + + def onLogout(self, user): + ''' + Invoked by Service when an user login is detected + This CAN be overridden by modules + This method is invoked whenever the client (user space agent) notifies the server (Service) that a user has logged in. + This method is run on its own thread + ''' + pass + + # ************************************* + # * Helper, convenient helper methods * + # ************************************* + def sendClientMessage(self, message, data): + ''' + Sends a message to connected ipc clients + By convenience, it uses the "current" moduel name as destination module name also. + If you need to send a message to a different module, you can use self.service.sendClientMessage(module, message, data) instead + og this helmer + ''' + self.service.sendClientMessage(self.name, message, data) + + def sendScriptMessage(self, script): + self.service.sendScriptMessage(script) + + def sendLogoffMessage(self): + self.service.sendLogoffMessage() + + def sendPopupMessage(self): + self.service.sendPopupMessage() diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/changelog.Debian.gz b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/changelog.Debian.gz new file mode 100644 index 0000000..3de583a Binary files /dev/null and b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/changelog.Debian.gz differ diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/copyright b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/copyright new file mode 100644 index 0000000..7b6ef31 --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/copyright @@ -0,0 +1,26 @@ +Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135 +Name: ogagent +Maintainer: Ramón M. Gómez +Source: https://opengnsys.es + +Copyright: 2014 Virtual Cable S.L.U. +License: BSD-3-clause + +License: GPL-2+ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +. +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +. +On Debian systems, the full text of the GNU General Public +License version 2 can be found in the file +`/usr/share/common-licenses/GPL-2'. diff --git a/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/readme.txt b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/readme.txt new file mode 100644 index 0000000..a2771de --- /dev/null +++ b/native/Sources/Clients/ogagent/oglive/debian/ogagent-oglive/usr/share/doc/ogagent-oglive/readme.txt @@ -0,0 +1,3 @@ +OGAgent is the agent intended for OpengGnsys interaction. + +Please, visit https://opengnsys.es for more information diff --git a/native/Sources/Includes/Database.cpp b/native/Sources/Includes/Database.cpp new file mode 100644 index 0000000..84add9c --- /dev/null +++ b/native/Sources/Includes/Database.cpp @@ -0,0 +1,203 @@ +// ******************************************************************************************************** +// Nombre del fichero: Database.cpp +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Descripción: +// Fichero de implementación de la clase Database para funciones de manipulación +// de bases de datos sobre un Servidor Mysql +// ******************************************************************************************************** +#include "Database.h" +// __________________________________________________________________________ +void ErrorHandler(Herror hr, char* ErrStr) +{ + sprintf(ErrStr,"Error:\n"); + sprintf(ErrStr,"%sCode = %d\n",ErrStr ,hr.nError); + sprintf(ErrStr,"%sDescription = %s",ErrStr, (char*) hr.dError); +} +// __________________________________________________________________________ +Database::Database() +{ + m_Cnn=NULL; + sprintf(m_ErrStr,"NULL POINTER"); +} +// __________________________________________________________________________ +void Database::GetErrorErrStr(char* ErrStr) +{ + sprintf(ErrStr,"%s",m_ErrStr); +} +// __________________________________________________________________________ +void Table::GetErrorErrStr(char* ErrStr) +{ + sprintf(ErrStr,"%s",m_ErrStr); +} +// __________________________________________________________________________ +bool Database::Open(char* UserName, char* Pwd,char* server,char*Bd) +{ + Herror hr; + m_Cnn=mysql_init(NULL); + if(m_Cnn==NULL){ + hr.nError=0; + strcpy(hr.dError,"Error en la Creación del objeto MYSQL"); + ErrorHandler(hr,m_ErrStr); + return(false); // Fallo de inicializaci� + } + + if(!mysql_real_connect(m_Cnn, server,UserName,Pwd,Bd, MYSQL_PORT,NULL,0)){ + mysql_error(m_Cnn); + hr.nError=mysql_errno(m_Cnn); + strcpy(hr.dError,mysql_error(m_Cnn)); + ErrorHandler(hr,m_ErrStr); + return(false); // Fallo de conexi� + } + hr.nError=0; + strcpy(hr.dError,"Success"); + ErrorHandler(hr,m_ErrStr); + return (true); +} +// __________________________________________________________________________ +bool Database::Close() +{ + mysql_close(m_Cnn); + return(true); +} +// __________________________________________________________________________ +bool Database::Execute(char* CmdStr) +{ + Herror hr; + if (mysql_query(m_Cnn,CmdStr)){ // Ejecuta la consulta + mysql_error(m_Cnn); + hr.nError=mysql_errno(m_Cnn); + strcpy(hr.dError,mysql_error(m_Cnn)); + ErrorHandler(hr,m_ErrStr); + mysql_close(m_Cnn); + return(false); // Fallo de conexión + } + hr.nError=0; + strcpy(hr.dError,"Success"); + ErrorHandler(hr,m_ErrStr); + return (true); +} +// __________________________________________________________________________ +bool Database::Execute(char* CmdStr, Table& Tbl) +{ + Herror hr; + if (mysql_query(m_Cnn,CmdStr)) { // Ejecuta la consulta + mysql_error(m_Cnn); + hr.nError=mysql_errno(m_Cnn); + strcpy(hr.dError,mysql_error(m_Cnn)); + ErrorHandler(hr,m_ErrStr); + mysql_close(m_Cnn); + return(false); // Fallo de conexi� + } + + hr.nError=0; + strcpy(hr.dError,"Success"); + ErrorHandler(hr,m_ErrStr); + + Tbl.m_Rec = mysql_store_result(m_Cnn) ; // Toma el recordset + if(Tbl.m_Rec){ + Tbl.row=mysql_fetch_row(Tbl.m_Rec); + Tbl.fields = mysql_fetch_fields(Tbl.m_Rec); + Tbl.num_fields = mysql_num_fields(Tbl.m_Rec); + Tbl.numreg=mysql_num_rows(Tbl.m_Rec); + Tbl.eof=Tbl.numreg==0; // Consulta vacia + } + return (true); +} +// __________________________________________________________________________ +void Database::liberaResult (Table& Tbl) { + //Free resources after mysql_store_result + mysql_free_result(Tbl.m_Rec); +} +// __________________________________________________________________________ +Table::Table() +{ + m_Rec=NULL; +} +// __________________________________________________________________________ +bool Table::ISEOF() +{ + return(eof); +} +// __________________________________________________________________________ +bool Table::Get(const char* FieldName, char *FieldValue) +{ + char * aux; + aux=tomadato(FieldName); + if(aux) + strcpy(FieldValue,aux); + else + strcpy(FieldValue,""); + return(true); +} +// __________________________________________________________________________ +bool Table::Get(const char* FieldName,int &FieldValue) +{ + char *aux; + aux=tomadato(FieldName); + if(aux) + FieldValue=atoi(aux); + else + FieldValue=0; + return(true); +} +// __________________________________________________________________________ +bool Table::Get(const char* FieldName,char &FieldValue) +{ + char *aux; + aux=tomadato(FieldName); + FieldValue=aux[0]; + return(true); +} +// __________________________________________________________________________ +char* Table::tomadato(const char* FieldName) +{ + Herror hr; + unsigned int i; + + for(i = 0; i < num_fields; i++){ + if(strcmp((char*)fields[i].name,FieldName)==0){ + sprintf(m_ErrStr,"Success"); + return((char*)row[i]); + } + } + hr.nError=-1; + strcpy(hr.dError,"El nombre del campo no existe"); + ErrorHandler(hr,m_ErrStr); + return(NULL); // No existe el nombre del campo en la tabla +} +// __________________________________________________________________________ + +bool Table::MoveNext() +{ + eof=false; + row=mysql_fetch_row(m_Rec); + if(row==NULL){ + if(!mysql_eof(m_Rec)) + return(false); // Fallo de lectura + else + eof=true; // Fin de fichero + } + return (true); +} +// __________________________________________________________________________ +bool Table::MoveFirst() +{ + my_ulonglong auxnumreg; + + auxnumreg=0; + mysql_data_seek(m_Rec,auxnumreg); + return (MoveNext()); +} +// __________________________________________________________________________ +bool Table::MoveLast() +{ + my_ulonglong auxnumreg; + auxnumreg=numreg; + auxnumreg--; + if(auxnumreg<0) auxnumreg=0; // Principio de fichero + mysql_data_seek(m_Rec,auxnumreg); + return (MoveNext()); + return (true); +} diff --git a/native/Sources/Includes/Database.h b/native/Sources/Includes/Database.h new file mode 100644 index 0000000..ae318bd --- /dev/null +++ b/native/Sources/Includes/Database.h @@ -0,0 +1,61 @@ +// ****************************************************************************************************** +// Aplicación HIDRA +// Copyright 2004 Jos�Manuel Alonso. Todos los derechos reservados. +// Fichero: Database.h +// Descripción: +// Fichero de cabecera de la clase Database para implementar funciones de manipulaci� +// de bases de datos sobre un Servidor Mysql +// ****************************************************************************************************** +#include +#include +#include +#include +// __________________________________________________________________________ +class Database; +class Table; +// __________________________________________________________________________ +class Database +{ +public: + MYSQL *m_Cnn; + char m_ErrStr[500]; + Database(); + bool Open(char* UserName, char* Pwd,char* server,char*Database); + bool OpenTbl(int Mode, char* CmdStr, Table& Tbl); + bool Close(void); + bool Execute(char* CmdStr); + bool Execute(char* CmdStr, Table& Tbl); + void liberaResult(Table& Tbl); + void GetErrorErrStr(char* ErrStr); +}; +// __________________________________________________________________________ +class Table{ + char* tomadato(const char* FieldName); +public: + bool eof,bof; + MYSQL_RES * m_Rec ; + MYSQL_FIELD *fields; + unsigned int num_fields; + MYSQL_ROW row ; + MYSQL_ROW_OFFSET ptr; + my_ulonglong numreg; + char m_ErrStr[500]; + Table(); + void GetErrorErrStr(char* ErrStr); + bool ISEOF(); + bool MoveNext(); + bool MovePrevious(); + bool MoveFirst(); + bool MoveLast(); + + bool Get(const char* FieldName, char* FieldValue); + bool Get(const char* FieldName,int &FieldValue); + bool Get(const char* FieldName,char &FieldValue); +}; +// __________________________________________________________________________ +class Herror +{ +public: + int nError; // C�igo del error + char dError[500]; // Descripción del error +}; diff --git a/native/Sources/Includes/Database.o b/native/Sources/Includes/Database.o new file mode 100644 index 0000000..aa88a57 Binary files /dev/null and b/native/Sources/Includes/Database.o differ diff --git a/native/Sources/Includes/ogAdmLib.c b/native/Sources/Includes/ogAdmLib.c new file mode 100644 index 0000000..2f0a714 --- /dev/null +++ b/native/Sources/Includes/ogAdmLib.c @@ -0,0 +1,1074 @@ +// ************************************************************************************************************************************************** +// Libreria: ogAdmLib +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmLib.c +// Descripción: Este fichero implementa una libreria de funciones para uso común de los servicios +// ************************************************************************************************************************************************** +// ________________________________________________________________________________________________________ +// Función: tomaHora +// +// Descripción: +// Devuelve la hora del sistema +// Parametros: +// Ninguno +// ________________________________________________________________________________________________________ +struct tm * tomaHora() +{ + time_t rawtime; + time ( &rawtime ); + return(localtime(&rawtime)); +} +// ________________________________________________________________________________________________________ +// Función: registraLog +// +// Descripción: +// Registra los eventos en un fichero log ya sean errores o información +// Parametros: +// - fileLog : Ruta completa del archivo de log +// - msg : Descripción del error +// - swe: Switch que indica si se debe recuperar además el literal de error del propio sistema operativo +// ________________________________________________________________________________________________________ +void registraLog(const char* filelog,const char *msg,int swe) +{ + FILE *flog; + struct tm * t; + + t = tomaHora(); + flog=fopen(filelog,"at"); + if(swe) + fprintf (flog,"%02d/%02d/%d %02d:%02d %s: %s\n",t->tm_mday,t->tm_mon+1,t->tm_year+1900,t->tm_hour,t->tm_min,msg,strerror(errno)); + else + fprintf (flog,"%02d/%02d/%d %02d:%02d %s\n",t->tm_mday,t->tm_mon+1,t->tm_year+1900,t->tm_hour,t->tm_min,msg); + fclose(flog); +} +// ________________________________________________________________________________________________________ +// Función: errorLog +// +// Descripción: +// Registra los sucesos de errores preestablecidos en el fichero de log +// Parametros: +// - coderr : Código del mensaje de error +// - swe: Switch que indica si se debe recuperar además el literal de error del propio sistema operativo +// ________________________________________________________________________________________________________ +void errorLog(const char *modulo, int coderr, int swe) { + char msglog[LONSUC]; + + sprintf(msglog, "*** Error: %s. Módulo %s", tbErrores[coderr], modulo); + registraLog(szPathFileLog, msglog, swe); +} +// ________________________________________________________________________________________________________ +// Función: errorInfo +// +// Descripción: +// Registra los sucesos de errores dinámicos en el fichero de log +// Parametros: +// - msgerr : Descripción del error +// - swe: Switch que indica si se debe recuperar además el literal de error del propio sistema operativo +// ________________________________________________________________________________________________________ +void errorInfo(const char *modulo, char *msgerr) { + char msglog[LONSUC]; + + sprintf(msglog, "*** Error: %s. Módulo %s", msgerr, modulo); + registraLog(szPathFileLog, msglog, FALSE); +} +// ________________________________________________________________________________________________________ +// Función: infoLog +// +// Descripción: +// Registra los sucesos de información en el fichero de log +// Parametros: +// - coderr : Código del mensaje de información +// ________________________________________________________________________________________________________ +void infoLog(int codinf) { + char msglog[LONSUC]; + + sprintf(msglog, "*** Info: %s", tbMensajes[codinf]); + registraLog(szPathFileLog, msglog, FALSE); +} +// ________________________________________________________________________________________________________ +// Función: infoDebug +// +// Descripción: +// Registra los mensajes de debugs en el fichero de log +// Parametros: +// - msgdeb : Descripción del mensaje de información +// ________________________________________________________________________________________________________ +void infoDebug(char* msgdeb) { + char msglog[LONSUC+15]; // Cadena de registro (reserva caracteres para el prefijo). + + sprintf(msglog, "*** Debug: %d-%s", ndebug, msgdeb); + registraLog(szPathFileLog, msglog, FALSE); +} +//______________________________________________________________________________________________________ +// Función: ValidacionParametros +// +// Descripción: +// Valida que los parametros de ejecución del programa sean correctos +// Parámetros: +// - argc: Número de argumentos +// - argv: Puntero a cada argumento +// - eje: Tipo de ejecutable (1=Servicio,2=Repositorio o 3=Cliente) +// Devuelve: +// - TRUE si los argumentos pasados son correctos +// - FALSE en caso contrario +// Especificaciones: +// La sintaxis de los argumentos es la siguiente +// -f Archivo de configuración del servicio +// -l Archivo de logs +// -d Nivel de debuger (mensages que se escribirán en el archivo de logs) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN validacionParametros(int argc, char*argv[],int eje) { + int i; + char modulo[] = "validacionParametros()"; + + switch(eje){ + case 1: // Administrador + strcpy(szPathFileCfg, "ogAdmServer.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmServer.log"); // de configuración y de logs + break; + case 2: // Repositorio + strcpy(szPathFileCfg, "ogAdmRepo.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmRepo.log"); // de configuración y de logs + break; + case 3: // Cliente OpenGnsys + strcpy(szPathFileCfg, "ogAdmClient.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmClient.log"); // de configuración y de logs + break; + case 4: // Servicios DHCP,BOOTP Y TFTP + strcpy(szPathFileCfg, "ogAdmBoot.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmBoot.log"); // de configuración y de logs + break; + case 5: // Agente + strcpy(szPathFileCfg, "ogAdmAgent.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmAgent.log"); // de configuración y de logs + break; + case 6: // Agente + strcpy(szPathFileCfg, "ogAdmWinClient.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmWinClient.log"); // de configuración y de logs + break; + case 7: // Agente + strcpy(szPathFileCfg, "ogAdmnxClient.cfg"); // Valores por defecto de archivos + strcpy(szPathFileLog, "ogAdmLnxClient.log"); // de configuración y de logs + break; + } + + ndebug = 1; // Nivel de debuger por defecto + + for (i = 1; (i + 1) < argc; i += 2) { + if (argv[i][0] == '-') { + switch (tolower(argv[i][1])) { + case 'f': + if (argv[i + 1] != NULL) + strcpy(szPathFileCfg, argv[i + 1]); + else { + errorLog(modulo, 10, FALSE); + return (FALSE); + } + break; + case 'l': + if (argv[i + 1] != NULL) + strcpy(szPathFileLog, argv[i + 1]); + else { + errorLog(modulo, 11, FALSE); + return (FALSE); + } + break; + case 'd': + if (argv[i + 1] != NULL) { + ndebug = atoi(argv[i + 1]); + if (ndebug < 1) + ndebug = 1; // Por defecto el nivel de debug es 1 + } else + ndebug = 1; // Por defecto el nivel de debug es 1 + break; + default: + errorLog(modulo, 12, FALSE); + exit(EXIT_FAILURE); + break; + } + } + } + return (TRUE); +} +//______________________________________________________________________________________________________ +// Función: reservaMemoria +// +// Descripción: +// Reserva memoria para una variable +// Parámetros: +// - lon: Longitud en bytes de la reserva +// Devuelve: +// Un puntero a la zona de memoria reservada que ha sido previamente rellena con zeros o nulos +//______________________________________________________________________________________________________ +char* reservaMemoria(int lon) +{ + char *mem; + + mem=(char*)malloc(lon); + if(mem!=NULL) + memset(mem,0,lon); + return(mem); +} +//______________________________________________________________________________________________________ +// Función: ampliaMemoria +// +// Descripción: +// Amplia memoria para una variable +// Parámetros: +// - ptr: Puntero al buffer de memoria que se quiere ampliar +// - lon: Longitud en bytes de la amplicación +// Devuelve: +// Un puntero a la zona de memoria reservada que ha sido previamente rellena con zeros o nulos +//______________________________________________________________________________________________________ +char* ampliaMemoria(char* ptr,int lon) +{ + char *mem; + + mem=(char*)realloc(ptr,lon*sizeof(char*)); + if(mem!=NULL) + return(mem); + return(NULL); +} +//______________________________________________________________________________________________________ +// Función: liberaMemoria +// +// Descripción: +// Libera memoria para una variable +// Parámetros: +// - ptr: Puntero al buffer de memoria que se quiere liberar +// Devuelve: +// Nada +//______________________________________________________________________________________________________ +void liberaMemoria(void* ptr) +{ + if(ptr){ + free (ptr); + } +} +// ________________________________________________________________________________________________________ +// Función: splitCadena +// +// Descripción: +// Trocea una cadena según un carácter delimitador +// Parámetros: +// - trozos: Array de punteros a cadenas +// - cadena: Cadena a trocear +// - chd: Carácter delimitador +// Devuelve: +// Número de trozos en que se divide la cadena +// ________________________________________________________________________________________________________ +int splitCadena(char **trozos,char *cadena, char chd) +{ + int w=0; + if(cadena==NULL) return(w); + + trozos[w++]=cadena; + while(*cadena!='\0'){ + if(*cadena==chd){ + *cadena='\0'; + if(*(cadena+1)!='\0') + trozos[w++]=cadena+1; + } + cadena++; + } + return(w); // Devuelve el número de trozos +} +// ________________________________________________________________________________________________________ +// Función: sustituir +// +// Descripción: +// Sustituye las apariciones de un caracter por otro en una cadena +// Parámetros: +// - cadena: Cadena a convertir +// - cho: Caracter a sustituir +// - chs: Caracter sustituto +// ________________________________________________________________________________________________________ +void sustituir(char *cadena,char cho,char chs) +{ + int x=0; + + while(cadena[x]!=0) { + if (cadena[x]==cho) + cadena[x]=chs; + x++; + } +} +// ________________________________________________________________________________________________________ +// Función: escaparCadena +// +// Descripción: +// Sustituye las apariciones de un caracter comila simple ' por \' +// Parámetros: +// - cadena: Cadena a escapar +// Devuelve: +// La cadena con las comillas simples sustituidas por \' +// ________________________________________________________________________________________________________ +char* escaparCadena(char *cadena) +{ + int b,c; + char *buffer; + + buffer = (char*) reservaMemoria(strlen(cadena)*2); // Toma memoria para el buffer de conversión + if (buffer == NULL) { // No hay memoria suficiente para el buffer + return (FALSE); + } + + c=b=0; + while(cadena[c]!=0) { + if (cadena[c]=='\''){ + buffer[b++]='\\'; + buffer[b++]='\''; + } + else{ + buffer[b++]=cadena[c]; + } + c++; + } + return(buffer); +} +// ________________________________________________________________________________________________________ +// Función: StrToUpper +// +// Descripción: +// Convierta una cadena en mayúsculas +// Parámetros: +// - cadena: Cadena a convertir +// ________________________________________________________________________________________________________ +char* StrToUpper(char *cadena) +{ + int x=0; + + while(cadena[x]!=0) { + if (cadena[x] >= 'a' && cadena[x] <= 'z') { + cadena[x] -= 32; + } + x++; + } + return(cadena); +} +// ________________________________________________________________________________________________________ +// Función: StrToUpper +// +// Descripción: +// Convierta una cadena en mayúsculas +// Parámetros: +// - cadena: Cadena a convertir +// ________________________________________________________________________________________________________ +char* StrToLower(char *cadena) +{ + int x=0; + + while(cadena[x]!=0) { + if (cadena[x] >= 'A' && cadena[x] <= 'Z') { + cadena[x] += 32; + } + x++; + } + return(cadena); +} +// ________________________________________________________________________________________________________ +// Función: INTROaFINCAD +// +// Descripción: +// Cambia caracteres INTROS por fin de cadena ('\0') en una trama +// Parametros: +// - parametros: Puntero a los parametros de la trama +// - lon: Longitud de la cadena de parametros +// ________________________________________________________________________________________________________ +void INTROaFINCAD(TRAMA* ptrTrama) +{ + char *i,*a,*b; + + a=ptrTrama->parametros; + b=a+ptrTrama->lonprm; + for(i=a;iparametros; + b=a+ptrTrama->lonprm; + for(i=a;iparametros; + b=a+ptrTrama->lonprm; + for(pos=a;pos=0;i--){ + if(cadena[i]<32) + cadena[i]='\0'; + else + return(cadena); + } + return(cadena); +} +// ________________________________________________________________________________________________________ +// Función: mandaTrama +// +// Descripción: +// Envía una trama por la red +// Parametros: +// - sock : El socket del host al que se dirige la trama +// - trama: El contenido de la trama +// - lon: Longitud de la parte de parametros de la trama que se va a mandar +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN mandaTrama(SOCKET *sock, TRAMA* ptrTrama) +{ + int lonprm; + char *buffer,hlonprm[LONHEXPRM+1]; + BOOLEAN res; + + lonprm=strlen(ptrTrama->parametros); + sprintf(hlonprm,"%05X",LONGITUD_CABECERATRAMA+LONHEXPRM+lonprm); // Convierte en hexadecimal la longitud + + buffer=reservaMemoria(LONGITUD_CABECERATRAMA+LONHEXPRM+lonprm); // Longitud total de la trama + if(buffer==NULL) + return(FALSE); + memcpy(buffer,ptrTrama,LONGITUD_CABECERATRAMA); // Copia cabecera de trama + memcpy(&buffer[LONGITUD_CABECERATRAMA],hlonprm,LONHEXPRM); // Copia longitud de la trama + memcpy(&buffer[LONGITUD_CABECERATRAMA+LONHEXPRM],ptrTrama->parametros,lonprm); + res=sendData(sock,buffer,LONGITUD_CABECERATRAMA+LONHEXPRM+lonprm); + liberaMemoria(buffer); + return (res); +} +// ________________________________________________________________________________________________________ +// Función: sendData +// +// Descripción: +// Envía datos por la red a través de un socket +// Parametros: +// - sock : El socket por donde se envía +// - datos: El contenido a enviar +// - lon: Cantidad de bites a enviar +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN sendData(SOCKET *sock, char* datos,int lon) +{ + int idx,ret; + idx = 0; + while (lon > 0) { + ret = send(*sock,&datos[idx],lon, 0); + if (ret == 0) { // Conexión cerrada por parte del cliente (Graceful close) + break; + } + else{ + if (ret == SOCKET_ERROR) + return (FALSE); + } + lon -= ret; + idx += ret; + } + return (TRUE); +} +// ________________________________________________________________________________________________________ +// Función: recibeTrama +// +// Descripción: +// Recibe una trama por la red +// Parametros: +// - sock : El socket del cliente +// - trama: El buffer para recibir la trama +// Devuelve: +// Un puntero a una estrucutra TRAMA o NULL si ha habido algún error +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +TRAMA* recibeTrama(SOCKET *sock) +{ + int ret,lon,lSize; + char *buffer,*bufferd,bloque[LONBLK],*hlonprm; + TRAMA * ptrTrama; + + lon=lSize=0; + do{ + if(!recData(sock,bloque,LONBLK,&ret)) // Lee bloque + return(NULL); + + if (lon==0 && lSize==0 && ret==0) // Comprueba trama válida + return(NULL); + + if(lSize==0){ // Comprueba tipo de trama y longitud total de los parámetros + if (strncmp(bloque, "@JMMLCAMDJ_MCDJ",15)!=0) + return(NULL); // No se reconoce la trama + hlonprm=reservaMemoria(LONHEXPRM+1); + if(!hlonprm) return(NULL); + memcpy(hlonprm,&bloque[LONGITUD_CABECERATRAMA],LONHEXPRM); + lSize=strtol(hlonprm,NULL,16); // Longitud total de la trama con los parametros encriptados + liberaMemoria(hlonprm); + buffer=(char*)reservaMemoria(lSize); // Toma memoria para la trama completa + if(!buffer) + return(NULL); + } + + if(ret>0){ // Datos recibidos + memcpy(&buffer[lon],bloque,ret); // Añade bloque + lon+=ret; + } + }while(lonparametros,bufferd,lon); + liberaMemoria((char*)buffer); + ptrTrama->lonprm=lon; // Almacena longitud de los parámetros ya desencriptados + return(ptrTrama); +} +// ________________________________________________________________________________________________________ +// Función: recData +// +// Descripción: +// Recibe datos por la red a través de un socket +// Parametros: +// - sock : El socket por el que se reciben los datos +// - datos: El buffer donde se almacenan +// - lon: Cantidad máxima de bites a recibir +// - ret: Cantidad de bites recibidos (Parámetro de salida) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN recData(SOCKET *sock, char* buffer,int lon,int* ret) +{ + *ret = 0; + + while (TRUE) { // Bucle para recibir datos del cliente + *ret = recv(*sock,buffer, lon, 0); + if (*ret == 0) // Conexión cerrada por parte del cliente (Graceful close) + break; + else { + if (*ret == SOCKET_ERROR) { + return (FALSE); + } else + // Datos recibidos + break; + } + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: enviaFlag +// +// Descripción: +// Envia una señal de sincronización +// Parámetros: +// - socket_c: (Salida) Socket utilizado para el envío (operativo) +// - ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN enviaFlag(SOCKET *socket_c,TRAMA *ptrTrama) +{ + char modulo[] = "enviaFlag()"; + if (!mandaTrama(socket_c,ptrTrama)) { + errorLog(modulo,26,FALSE); + return (FALSE); + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: recibeFlag +// +// Descripción: +// Recibe una señal de sincronización +// Parámetros: +// - socket_c: Socket utilizadopara la recepción (operativo) +// - ptrTrama: (Salida) Contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN recibeFlag(SOCKET *socket_c,TRAMA *ptrTrama) +{ + ptrTrama=recibeTrama(socket_c); + if(!ptrTrama){ + return(FALSE); + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: URLEncode +// +// Descripción: +// Codifica una cadena en UrlEncode +// Parámetros: +// - src: La cadena a decodificar +// Devuelve: +// La cadena decodificada +// ________________________________________________________________________________________________________ +char* URLEncode(char *src) +{ + char *dest; + int i,j=0,lon; + + lon=strlen(src); + dest=(char*)reservaMemoria(lon*2); // Reserva buffer para la cadena + for(i=0;i0) + fwrite(buffer,1,lon,f); // Lee el contenido del fichero + }while(lon>0); // Bucle para recibir datos del cliente + fclose(f); + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: initParammetros +// +// Descripción: +// Libera memoria del buffer de los parametros de la trama y vuelve a reservar espacio +// Parámetros: +// - parametros : Puntero a la zona donde están los parametros de una trama +// - lon : Tamaño de la nueva reserva de espacio para los parametros +// Devuelve: +// Un puntero a la nueva zona de memoria o NULL si ha habido algún error +// Especificaciones: +// En caso de que el parámetro lon valga cero el tamaño a reservar será el estandar +//______________________________________________________________________________________________________ +BOOLEAN initParametros(TRAMA* ptrTrama,int lon) +{ + if(lon==0) lon=LONGITUD_PARAMETROS; + ptrTrama->parametros=(char*)ampliaMemoria(ptrTrama->parametros,lon); + if(!ptrTrama->parametros) + return(FALSE); + else + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: TCPConnect +// +// Descripción: +// Crea un socket y lo conecta a un servidor +// Parámetros: +// - ips : La Dirección IP del servidor +// - port : Puerto para la comunicación +// Devuelve: +// Un socket para comunicaciones por protocolo TCP +//______________________________________________________________________________________________________ +SOCKET TCPConnect(char *ips,char* port) +{ + SOCKET s; + struct sockaddr_in server; + char modulo[] = "TCPConnect()"; + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s == INVALID_SOCKET){ + return (INVALID_SOCKET); + } + server.sin_family = AF_INET; + server.sin_port = htons((short)atoi(port)); + server.sin_addr.s_addr = inet_addr(ips); + + if (connect(s, (struct sockaddr *)&server, sizeof(server)) == INVALID_SOCKET){ + errorLog(modulo,38,TRUE); + return (INVALID_SOCKET); + } + + return(s); +} +//______________________________________________________________________________________________________ +// Función: AbreConexion +// +// Descripción: +// Abre la conexión entre el cliente y el servidor de administración +// Parámetros: +// - Ninguno +// Devuelve: +// Un socket de cliente para comunicaciones +//______________________________________________________________________________________________________ +SOCKET abreConexion(void) +{ + int swloop=0; + SOCKET s; + + while(swlooparroba='@'; // Cabecera de la trama + strncpy(ptrTrama->identificador,"JMMLCAMDJ_MCDJ",14); // identificador de la trama + ptrTrama->tipo=tipo; // Tipo de mensaje + + if (!mandaTrama(socket_c,ptrTrama)) { + errorLog(modulo,26,FALSE); + return (FALSE); + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: recibeMensaje +// +// Descripción: +// Recibe un mensaje del servidor de Administración +// Parámetros: +// - socket_c: Socket utilizadopara la recepción +// - ptrTrama: (Salida) Contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +TRAMA* recibeMensaje(SOCKET *socket_c) +{ + TRAMA* ptrTrama; + char modulo[] = "recibeMensaje()"; + + ptrTrama=recibeTrama(socket_c); + if(!ptrTrama){ + errorLog(modulo,17,FALSE); + return(NULL); + } + return(ptrTrama); +} + +// ________________________________________________________________________________________________________ diff --git a/native/Sources/Includes/ogAdmLib.h b/native/Sources/Includes/ogAdmLib.h new file mode 100644 index 0000000..42279a3 --- /dev/null +++ b/native/Sources/Includes/ogAdmLib.h @@ -0,0 +1,319 @@ +// ************************************************************************************************************************************************** +// Libreria: ogAdmLib +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmLib.h +// Descripción: Este fichero implementa el archivo de cabecera de la libreria ogAdmLib +// ************************************************************************************************************************************************** +// ________________________________________________________________________________________________________ +// Valores definidos +// ________________________________________________________________________________________________________ +#define LONSTD 1024 // Longitud de memoria estandar +#define LONINT 16 // Longitud de memoria estandar para un número entero +#define LONFIL 1024 // Longitud de memoria estandar para nombres de archivo completos (incluido path) +#define LONIP 16 // Longitud de memoria estandar para cadenas que contiene una dirección IP +#define LONMAC 16 // Longitud de memoria estandar para cadenas que contiene una dirección MAC +#define LONSQL 8192 // Longitud de memoria estandar para una sentencia SQL +#define LONPRM 4098 // Longitud estandar de los parámetros del fichero de configuración del servicio +#define LONSCP 4098 // Longitud estandar de los parámetros de las tramas +#define LONFUN 512 // Longitud estandar de los nombres de las funciones que procesan las tramas +#define LONSUC 4098 // Longitud de los mensajes de sucesos +#define LONBLK 8192 // Longitud de los paquetes de tramas leidos cada vez +#define MAXPRM 20 // Máximo número de parámeros del fichero de configuración del servicio +#define MAXPAR 128 // Maximo numero de particiones manejadas por el sistema, ahora con GPT es 128 +#define MAXLONURL 1024 // Longitud máxima de una dirección url con parámetros + +#define LONHEXPRM 5 // Longitud del campo que contiene el tamaño de la cadena de parámetros +#define LONGITUD_CABECERATRAMA 16 // Longitud de la cabecera de las tramas +#define LONGITUD_PARAMETROS 8192 // Longitud estandar de la información de la trama (parámetros) +#define MAXCMD_PARAMETROS 200 // Máximo número de parámetros de una trama + +#define MAXIMOS_CLIENTES 4000 // Máximo número de conexiones con ordenadores clientes +#define MAXIMAS_FUNCIONES LONSTD // Máximo número de funciones que procesan los mensajes entre servicio y clientes +#define MAXIMAS_LINEAS 3000 // Longitud máxima de lineas en un archivo de comandos + +#define AUTOINCORPORACION_OFF 0x0000 // Los ordenadores no se pueden dar de alta automáticamente +#define AUTOINCORPORACION_ONA 0x0001 // Los ordenadores se pueden dar de alta automáticamente si existe el aula +#define AUTOINCORPORACION_ONX 0x0002 // Los ordenadores se pueden dar de alta automáticamentee y si no existe el aula la crea + +#define DEBUG_BAJO 1 // Nivel de debug bajo +#define DEBUG_MEDIO 2 // Nivel de debug medio +#define DEBUG_ALTO 3 // Nivel de debug alto +#define DEBUG_MAXIMO 4 // Nivel de debug máximo + +#define CLIENTE_OCUPADO "BSY" // Cliente ocupado +#define CLIENTE_APAGADO "OFF" // Cliente apagado +#define CLIENTE_INICIANDO "INI" // Cliente iniciando + +#define CLIENTE_OPENGNSYS "OPG" // Cliente Opengnsys + +#define CLIENTE_WIN "WIN" // Cliente Windows genérico +#define CLIENTE_WNT "WNT" // Windows NT +#define CLIENTE_W2K "W2K" // Windows 2000 +#define CLIENTE_WS2 "WS2" // Windows Server 2003 +#define CLIENTE_WXP "WXP" // Cliente Windows XP +#define CLIENTE_W95 "W95" // Windows 95 +#define CLIENTE_W98 "W98" // Windows 98 +#define CLIENTE_WML "WML" // Windows Milenium +#define CLIENTE_MS2 "MS2" // MsDos +#define CLIENTE_WVI "WVI" // Cliente Windows Vista +#define CLIENTE_WI7 "WI7" // Cliente Windows 7 + +#define CLIENTE_LNX "LNX" // Cliente Linux + +#define ACCION_SINRESULTADO 0 // Sin resultado +#define ACCION_EXITOSA 1 // Finalizada con éxito +#define ACCION_FALLIDA 2 // Finalizada con errores + +#define ACCION_INICIADA 1 // Acción activa +#define ACCION_DETENIDA 2 // Acción momentanemente parada +#define ACCION_FINALIZADA 3 // Accion finalizada + +#define EJECUCION_COMANDO 1 +#define EJECUCION_PROCEDIMIENTO 2 +#define EJECUCION_TAREA 3 +#define EJECUCION_RESERVA 4 + +#define AMBITO_CENTROS 0x01 +#define AMBITO_GRUPOSAULAS 0x02 +#define AMBITO_AULAS 0x04 +#define AMBITO_GRUPOSORDENADORES 0x08 +#define AMBITO_ORDENADORES 0x10 + +// Código de los tipos de mensajes +#define MSG_COMANDO '1' // Mensaje del tipo comando +#define MSG_NOTIFICACION '2' // Respuesta a la ejecución un comando +#define MSG_PETICION '3' // Petición de cualquier actuación +#define MSG_RESPUESTA '4' // Respuesta a una petición +#define MSG_INFORMACION '5' // Envío de cualquier información sin espera de confirmación o respuesta + +#define ANNOREF 2009 // Año de referencia base + +#define LONGITUD_SCRIPTSALIDA 131072 // Longitud máxima de la información devuelta por una función de interface +#define MAXARGS 16 // Número máximo de argumentos enviados a un scripts +#define MAXCNX 5 // Máximos intentos de conexión al servidor de Administración + +#define PUERTO_WAKEUP 9 // Puerto wake up + +#define MAXHARDWARE 128 // Máximos elementos hardware a detectar +#define MAXSOFTWARE 8096 // Máximos elementos software a detectar +// ________________________________________________________________________________________________________ +// Tipos definidos +// ________________________________________________________________________________________________________ +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef int BOOLEAN; +typedef char BYTE; +typedef int SOCKET; +typedef void* LPVOID; + +#define TRUE 1 +#define FALSE 0 + +#define SOCKET_ERROR (-1) +#define INVALID_SOCKET (SOCKET)(~0) + +#define LEER 0 +#define ESCRIBIR 1 + +#define CHARNULL '\0' + +// ________________________________________________________________________________________________________ +// Variables globales +// ________________________________________________________________________________________________________ +char szPathFileCfg[LONSTD],szPathFileLog[LONSTD]; +int ndebug; // Nivel de debuger + +typedef struct{ // Estructura de las tramas + char arroba; // Caracter arroba siempre + char identificador[14]; // Identificador de la trama, siempre JMMLCAMDJ_MCDJ + char tipo; // Tipo de mensaje + long lonprm; // Longitud en hexadecimal de los parámetros + char *parametros; // Parámetros de la trama +}TRAMA; +// ________________________________________________________________________________________________________ +// Tabla de errores +// ________________________________________________________________________________________________________ +const char* tbErrores[]={"Se han generado errores. No se puede continuar la ejecución de este módulo",\ + "001-El nombre del fichero de configuración del programa está vacío",\ + "002-No existe fichero de configuración del programa",\ + "003-No hay memoria suficiente para el buffer",\ + "004-Error en el fichero de configuración del programa. No se ha definido el parámetro SERVIDORADM",\ + "005-Error en el fichero de configuración del programa. No se ha definido el parámetro PUERTO",\ + "006-Error en el fichero de configuración del programa. No se ha definido el parámetro USUARIO",\ + "007-Error en el fichero de configuración del programa. No se ha definido el parámetro PASSWORD",\ + "008-Error en el fichero de configuración del programa. No se ha definido el parámetro DATASOURCE",\ + "009-Error en el fichero de configuración del programa. No se ha definido el parámetro CATALOG",\ + "010-Error en los parámetros de ejecución del programa. Debe especificar el fichero de configuración",\ + "011-Error en los parámetros de ejecución del programa. Debe especificar el fichero de log",\ + "012-Error de sintaxis en los parámetros de ejecución del programa: Debe especificar -f nombre_del_fichero_de_configuración_del_programa -l nombre_del_fichero_de_log_del_programa -d nivel de debug",\ + "013-Error al crear socket ***socket() fallo",\ + "014-Error al enlazar socket al interface ***bind() fallo",\ + "015-Error al acceptar conexión de clientes ***accept() fallo",\ + "016-Error al crear hebra de cliente en módulo main()",\ + "017-Error al recibir trama ***recv() fallo",\ + "018-No se reconoce el mensaje enviado",\ + "019-Trama recibida NO válida",\ + "020-No se puede establecer conexión con la base de datos",\ + "021-No se han podido recuperar los datos de la consulta o bien insertar, modificar o eliminar datos",\ + "022-El cliente no se ha sido dado de alta en la base de datos del sistema. Se rechaza su petición de inclusión",\ + "023-Ha habido algún problema en la incorporación automática del cliente",\ + "024-Ha habido algún problema en la actualización de la configuración del cliente",\ + "025-La tabla de clientes está llena, no pueden registrarse más clientes en el sistema",\ + "026-Error al enviar trama ***send() fallo",\ + "027-No se encuentra Repositorio del cliente",\ + "028-Ha ocurrido algún error al tomar las particiones",\ + "029-Ha ocurrido algún problema en el proceso de inclusión del cliente. Se rechaza su petición",\ + "030-Ha ocurrido algún problema en el proceso de respuesta al comando",\ + "031-No se ha encontrado la acción a notificar es posible que se haya eliminado el registro",\ + "032-Ha ocurrido algún problema en el envío del comando",\ + "033-Error en el fichero de configuración del programa. No se ha definido el parámetro PATHSCRIPTS",\ + "034-Error en el fichero de configuración del programa. No se ha definido el parámetro URLMENU",\ + "035-Error en el fichero de configuración del programa. No se ha definido el parámetro URLMSG",\ + "036-No se ha podido recuperar la configuración de las particiones del disco",\ + "037-Ha ocurrido algún problema en el proceso de inclusión del cliente",\ + "038-No se ha podido establecer conexión con el Servidor de Administración",\ + "039-Ha ocurrido algún problema al procesar la trama recibida",\ + "040-Se han recibido parámetros con valores no válidos",\ + "041-Ha ocurrido algún problema en el proceso de inclusión del cliente",\ + "042-Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración",\ + "043-Ha ocurrido algún problema al enviar una petición de comandos interactivos al Servidor de Administración",\ + "044-Ha ocurrido algún problema al enviar una respuesta de comandos al servidor",\ + "045-Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración",\ + "046-Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración",\ + "047-El cliente no está registrado en la tabla de sockest del sistema",\ + "048-Error al configurar opción BROADCAST para socket: setsockopt(SO_BROADCAST)",\ + "049-Error al enviar trama magic packet",\ + "050-Ha ocurrido algún problema al enviar un fichero por la red",\ + "051-Error en el fichero de configuración del programa. No se ha definido el parámetro PATHLOGFIL",\ + "052-No se puede crear archivo temporal para ejecución de Comandos",\ + "053-Ha ocurrido algún problema al procesar el Inventario Hardware del cliente",\ + "054-Existe un tipo de hardware que no está registrado",\ + "055-Ha ocurrido algún problema al actualizar el hardware del cliente",\ + "056-Error en el fichero de configuración del programa. No se ha definido el parámetro PATHINTERFACE",\ + "057-Ha ocurrido algún problema al enviar un archivo por la red",\ + "058-Ha ocurrido algún problema al recibir un archivo por la red",\ + "059-Error al crear la hebra DHCP o BOOTP",\ + "060-Error al crear la hebra TFTP",\ + "061-Error al crear socket para servicio DHCP",\ + "062-Error al enlazar socket con interface para servicio DHCP",\ + "063-No hay puertos libres para la hebra del servicio",\ + "064-Error al crear estructura de control para protocolo DHCP",\ + "065-Error al recibir mensaje DHCP. Se para el servicio",\ + "066-Error al crear la hebra cliente DHCP",\ + "067-Error al crear socket para servicio BOOTP",\ + "068-Error al enlazar socket con interface para servicio BOOTP",\ + "069-Error al crear estructura de control para protocolo BOOTP",\ + "070-Error al recibir mensaje BOOTP. Se para el servicio",\ + "071-Error al crear la hebra cliente BOOTP",\ + "072-Error al crear socket para servicio TFTP",\ + "073-Error al enlazar socket con interface para servicio TFTP",\ + "074-Error al crear estructura de control para protocolo TFTP",\ + "075-Error al recibir mensaje TFTP. Se para el servicio",\ + "076-Error al crear la hebra cliente TFTP",\ + "077-No se encontró opción DHCP",\ + "078-ERROR TFTP",\ + "079-Error al recibir mensaje TFTP en hebra cliente",\ + "080-Error al recibir mensaje DHCP",\ + "081-Error al crear socket de usuario para hebra",\ + "082-Ha ocurrido algún problema al procesar el Inventario software del cliente",\ + "083-Ha ocurrido algún problema al actualizar el software del cliente",\ + "084-Ha ocurrido algún problema al reiniciar la sesión del cliente",\ + "085-No se ha podido recuperar la dirección IP del cliente",\ + "086-Error al ejecutar el comando",\ + "087-Error al leer o escribir el contenido del archivo de eco de consola remota",\ + "088-Ha habido algún problerma al procesar la caché",\ + "089-Error en el fichero de configuración del programa. No se ha definido el parámetro URLMENU",\ + "090-Error en el fichero de configuración del programa. No se ha definido el parámetro URLMSG",\ + "091-Ha habido algún problema al enviar un mensaje de tipo petición al Servidor",\ + "092-Error en el fichero de configuración del programa. No se ha definido el parámetro IPLOCAL",\ + "093-No se puede cargar la librería Windows para trabajar con sockets",\ + "094-Ha habido algún problerma al procesar la actualización después de crear una imagen",\ + "095-Ha habido algún problerma al procesar la actualización después de restaurar una imagen",\ + "096-Ha habido algún problerma al procesar la actualización después de crear un software incremental",\ + "097-Este fichero de log está obsoleto, este proceso usa ahora syslog para gestionar los mensajes de log",\ +}; +// ________________________________________________________________________________________________________ +// Tabla de mensajes +// ________________________________________________________________________________________________________ +const char* tbMensajes[]={"",\ + "001-Inicio de sesion",\ + "002-Petición de inclusión de cliente",\ + "003-Abriendo sesión en el servidor de Administración",\ + "004-Cliente iniciado",\ + "005-Ejecución de archivo Autoexec",\ + "006-Procesa comandos pendientes",\ + "007-Acciones pendientes procesadas",\ + "008-Ejecución del script",\ + "009-Parámetro del script",\ + "010-Ha ocurrido algún error en la creación del proceso hijo",\ + "011-Aviso: La información de salida del script excede de la longitud permitida. Puede haberse truncado",\ + "012-Información devuelta por el script",\ + "013-Estatus de finalización del script",\ + "014-Configuración de particiones",\ + "015-Enviando petición de inclusión en el sistema al Servidor de Administración",\ + "016-Recibiendo respuesta de inclusión desde el Servidor de Administración",\ + "017-Enviando petición de comandos o tareas pendientes al Servidor de Administración",\ + "018-Recibiendo respuesta de comandos o tareas pendientes desde el Servidor de Administración",\ + "019-Disponibilidad de comandos activada",\ + "020-Disponibilidad de comandos desactivada",\ + "021-Ejecución de comando",\ + "022-Sin eco",\ + "023-Procesando caché",\ + "024-Repositorio iniciado",\ + +}; +// ________________________________________________________________________________________________________ +// Prototipo de funciones +// ________________________________________________________________________________________________________ +struct tm * tomaHora(); +void registraLog(const char *,const char *,int ); +void errorLog(const char *,int ,int); +#define og_log(err, swe) errorLog(__FUNCTION__, err, swe) +void errorInfo(const char *,char *); +#define og_info(err) errorInfo(__FUNCTION__, err) +void infoLog(int); +void infoDebug(char*); +BOOLEAN validacionParametros(int,char**,int); +char* reservaMemoria(int); +char* ampliaMemoria(char*,int); +void liberaMemoria(void*); +BOOLEAN initParametros(TRAMA*,int); +int splitCadena(char **,char *, char); +void sustituir(char *,char ,char ); +char* StrToUpper(char *); +char* StrToLower(char *); +void INTROaFINCAD(TRAMA*); +void FINCADaINTRO(TRAMA*); +int cuentaIPES(char*); +char *tomaParametro(const char*,TRAMA*); +char *copiaParametro(const char*,TRAMA *); +BOOLEAN contieneIP(char *,char *); +char* rTrim(char *); +SOCKET TCPConnect(char *,char *); +SOCKET abreConexion(void); +BOOLEAN enviaMensaje(SOCKET *,TRAMA *,char); +TRAMA* recibeMensaje(SOCKET *); +BOOLEAN mandaTrama(SOCKET*,TRAMA*); +BOOLEAN sendData(SOCKET *, char* ,int ); +BOOLEAN enviaTrama(SOCKET *,TRAMA *); +TRAMA* recibeTrama(SOCKET*); +BOOLEAN recData(SOCKET *,char*,int,int*); +BOOLEAN sendFlag(SOCKET *, char* ,int ); +BOOLEAN recibeFlag(SOCKET*,TRAMA*); +char* URLEncode(char *); +char* URLDecode(char *); +char* leeArchivo(char*); +int lonArchivo(char *); +BOOLEAN escribeArchivo(char *,char*); +BOOLEAN sendArchivo(SOCKET *,char *); +BOOLEAN recArchivo(SOCKET *,char *); +SOCKET TCPConnect(char *,char*); + +#include /* for offsetof. */ + +#define container_of(ptr, type, member) ({ \ + typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + diff --git a/native/Sources/Services/ogAdmAgent/Makefile b/native/Sources/Services/ogAdmAgent/Makefile new file mode 100644 index 0000000..b9d39b9 --- /dev/null +++ b/native/Sources/Services/ogAdmAgent/Makefile @@ -0,0 +1,42 @@ +# makefile + +# Nombre del proyecto +PROYECTO := ogAdmAgent + +# Directorio de instalación +INSTALL_DIR := /opt/opengnsys + +# Opciones de compilacion +CFLAGS := $(shell mysql_config --cflags) +CFLAGS += -g -Wall -I../../Includes +CPPFLAGS := $(CFLAGS) + +# Opciones de linkado +LDFLAGS := -Wl,--no-as-needed $(shell mysql_config --libs) -lpthread + +# Ficheros objetos +OBJS := ../../Includes/Database.o sources/ogAdmAgent.o + + +all: $(PROYECTO) + +$(PROYECTO): $(OBJS) + g++ $(LDFLAGS) $(OBJS) -o $(PROYECTO) + +install: $(PROYECTO) + cp $(PROYECTO) $(INSTALL_DIR)/sbin + cp $(PROYECTO).cfg $(INSTALL_DIR)/etc + +clean: + rm -f $(PROYECTO) $(OBJS) + +uninstall: clean + rm -f /usr/local/sbin/$(PROYECTO) /usr/local/etc/$(PROYECTO).cfg + +sources/%.o: sources/%.cpp + g++ $(CPPFLAGS) -c -o"$@" "$<" + +sources/%.o: sources/%.c + gcc $(CFLAGS) -c -o"$@" "$<" + + diff --git a/native/Sources/Services/ogAdmAgent/ogAdmAgent.cfg b/native/Sources/Services/ogAdmAgent/ogAdmAgent.cfg new file mode 100644 index 0000000..20126d3 --- /dev/null +++ b/native/Sources/Services/ogAdmAgent/ogAdmAgent.cfg @@ -0,0 +1,7 @@ +ServidorAdm=SERVERIP +PUERTO=2008 +USUARIO=DBUSER +PASSWORD=DBPASSWORD +datasource=localhost +CATALOG=DATABASE + diff --git a/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.cpp b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.cpp new file mode 100644 index 0000000..6bf2351 --- /dev/null +++ b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.cpp @@ -0,0 +1,914 @@ +// ******************************************************************************************************** +// Servicio: ogAdmAgent +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmAgent.cpp +// Descripción: Este fichero implementa el servicio agente del sistema. Revisa a intervalos +// regulares la base de datos para comprobar si existen acciones programadas. +// ******************************************************************************************************** +#include "ogAdmAgent.h" +#include "ogAdmLib.c" +//________________________________________________________________________________________________________ +// Función: tomaConfiguracion +// +// Descripción: +// Lee el fichero de configuración del servicio +// Parámetros: +// filecfg : Ruta completa al fichero de configuración +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN tomaConfiguracion(char* filecfg) +{ + char modulo[] = "tomaConfiguracion()"; + + if (filecfg == NULL || strlen(filecfg) == 0) { + errorLog(modulo, 1, FALSE); // Fichero de configuración del servicio vacío + return (FALSE); + } + FILE *fcfg; + long lSize; + char * buffer, *lineas[MAXPRM], *dualparametro[2]; + int i, numlin, resul; + + fcfg = fopen(filecfg, "rt"); + if (fcfg == NULL) { + errorLog(modulo, 2, FALSE); // No existe fichero de configuración del servicio + return (FALSE); + } + + fseek(fcfg, 0, SEEK_END); + lSize = ftell(fcfg); // Obtiene tamaño del fichero. + rewind(fcfg); + buffer = (char*) reservaMemoria(lSize + 1); // Toma memoria para el buffer de lectura. + if (buffer == NULL) { // No hay memoria suficiente para el buffer + errorLog(modulo, 3, FALSE); + return (FALSE); + } + fread(buffer, 1, lSize, fcfg); // Lee contenido del fichero + buffer[lSize] = (char) NULL; + fclose(fcfg); + + servidoradm[0] = (char) NULL; //inicializar variables globales + puerto[0] = (char) NULL; + usuario[0] = (char) NULL; + pasguor[0] = (char) NULL; + datasource[0] = (char) NULL; + catalog[0] = (char) NULL; + + numlin = splitCadena(lineas, buffer, '\n'); + for (i = 0; i < numlin; i++) { + splitCadena(dualparametro, lineas[i], '='); + resul = strcmp(StrToUpper(dualparametro[0]), "SERVIDORADM"); + if (resul == 0) + strcpy(servidoradm, dualparametro[1]); + resul = strcmp(StrToUpper(dualparametro[0]), "PUERTO"); + if (resul == 0) + strcpy(puerto, dualparametro[1]); + resul = strcmp(StrToUpper(dualparametro[0]), "USUARIO"); + if (resul == 0) + strcpy(usuario, dualparametro[1]); + resul = strcmp(StrToUpper(dualparametro[0]), "PASSWORD"); + if (resul == 0) + strcpy(pasguor, dualparametro[1]); + resul = strcmp(StrToUpper(dualparametro[0]), "DATASOURCE"); + if (resul == 0) + strcpy(datasource, dualparametro[1]); + resul = strcmp(StrToUpper(dualparametro[0]), "CATALOG"); + if (resul == 0) + strcpy(catalog, dualparametro[1]); + } + if (servidoradm[0] == (char) NULL) { + errorLog(modulo, 4, FALSE); // Falta parámetro SERVIDORADM + return (FALSE); + } + if (puerto[0] == (char) NULL) { + errorLog(modulo, 5, FALSE); // Falta parámetro PUERTO + return (FALSE); + } + if (usuario[0] == (char) NULL) { + errorLog(modulo, 6, FALSE); // Falta parámetro USUARIO + return (FALSE); + } + if (pasguor[0] == (char) NULL) { + errorLog(modulo, 7, FALSE); // Falta parámetro PASSWORD + return (FALSE); + } + if (datasource[0] == (char) NULL) { + errorLog(modulo, 8, FALSE); // Falta parámetro DATASOURCE + return (FALSE); + } + if (catalog[0] == (char) NULL) { + errorLog(modulo, 9, FALSE); // Falta parámetro CATALOG + return (FALSE); + } + return (TRUE); +} +// ________________________________________________________________________________________________________ +// +// Función: diadelaSemana +// +// Descripción: +// Calcula el número del día de la semana que corresponde a una fecha +// Parámetros: +// - dia: Un día +// - mes: Un mes +// - anno: Un año +// Devuelve: +// El número del día de la semana: 1=Lunes, 2=martes ... 6=sábado 7=domingo +// ________________________________________________________________________________________________________ + +int diadelaSemana(WORD dia,WORD mes,WORD anno) +{ + int i,cont,dias_anuales; + int desplazamiento_dias=6; + int orddiasem; + + cont =0; + for (i=1900;i0) cociente++; + return(cociente); +} +// ________________________________________________________________________________________________________ +// +// Función: buscaAccion +// +// Descripción: +// Busca en la base de datos, acciones programadas +// Parámetros: +// - db: Objeto base de datos (operativo) +// - dia : Día actual del mes +// - mes : mes en curso +// - anno : Año en curso +// - hora : Hora actual +// - minutos : Minutos actuales +// - diasemana : Dia de la semana 1=lunes,2=martes ... ( 0 Domingo) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ + +BOOLEAN buscaAccion(Database db,WORD dia,WORD mes,WORD anno,WORD hora,WORD minutos,WORD diasemana) +{ + char msglog[LONSTD], sqlstr[LONSQL]; + Table tbl; + BYTE swampm,bitsemana; + int ordsem,ordulsem,ordiasem_1,maxdias; + int sesionprog; + char modulo[] = "buscaAccion()"; + + /* Año de comienzo */ + anno=anno-ANNOREF; // + /* Preparación hora */ + if(hora>11){ + hora-=12; + swampm=1; // Es P.M. + } + else + swampm=0; // Es am + /* Preparación semana */ + if(diasemana==0) diasemana=7; // El domingo + + // Cuestión semanas + ordiasem_1=diadelaSemana(1,mes,anno+2009); + ordsem=semanadelMes(ordiasem_1,dia); // Calcula el número de la semana + if (mes!=2) // Toma el último día de ese mes + maxdias=dias_meses[mes]; + else{ + if (bisiesto(anno+ANNOREF)) + maxdias=29; + else + maxdias=28; + } + ordulsem=semanadelMes(ordiasem_1,maxdias); // Calcula el número de la última semana + bitsemana=HEX_semanas[ordsem]; + if(ordsem==ordulsem) // Si es la última semana del mes + bitsemana|=HEX_semanas[6]; + + sprintf(sqlstr,"SELECT DISTINCT idprogramacion,tipoaccion,identificador,sesion,idcentro,"\ + "tareas.descripcion as descritarea"\ + " FROM programaciones"\ + " LEFT OUTER JOIN tareas ON tareas.idtarea=programaciones.identificador"\ + " WHERE suspendida=0 "\ + " AND (annos & %d <> 0) "\ + " AND (meses & %d<>0) "\ + " AND ((diario & %d<>0) OR (dias & %d<>0) OR (semanas & %d<>0))"\ + " AND (horas & %d<>0) AND ampm=%d AND minutos=%d",\ + HEX_annos[anno],\ + HEX_meses[mes],\ + HEX_dias[dia],\ + HEX_diasemana[diasemana],\ + bitsemana,\ + HEX_horas[hora],\ + swampm,minutos); + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(tbl.ISEOF()){ + return(TRUE); // No hay acciones programadas + } + + while(!tbl.ISEOF()){ + if(!tbl.Get("idprogramacion",idprogramacion)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("tipoaccion",tipoaccion)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("identificador",idtipoaccion)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("sesion",sesionprog)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("idcentro",idcentro)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + + if(tipoaccion==EJECUCION_COMANDO){ // Es una programación de un comando + return(ejecutarComando(db,idprogramacion,sesionprog)); + } + else{ + + if(tipoaccion==EJECUCION_TAREA){ + if(!tbl.Get("descritarea",descriaccion)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + return(ejecutarTarea(db,idprogramacion,idtipoaccion)); + } + else{ + if(tipoaccion==EJECUCION_RESERVA){ + EjecutarReserva(idtipoaccion,db); // Es una programación de un trabajo + } + } + } + tbl.MoveNext(); + } + return(TRUE); +} +// ________________________________________________________________________________________________________ +// +// Función: ejecutarComando +// +// Descripción: +// Ejecuta un comando programado +// Parámetros: +// - db: Objeto base de datos (operativo) +// - idcomando: Identificador del comando +// - sesion: Sesión correspondiente al comando cuando se grabó en la tabla acciones +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ + +BOOLEAN ejecutarComando(Database db,int idprogramacion,int sesion ) +{ + struct tm* st; + char msglog[LONSTD], sqlstr[LONSQL]; + char fechahorareg[24]; + char modulo[] = "ejecutarComando()"; + + st = tomaHora(); + sprintf(fechahorareg,"%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1, + st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec); + + sprintf(sqlstr,"UPDATE acciones SET estado=%d,idprogramacion=%d,fechahorareg='%s'"\ + " WHERE sesion=%d", ACCION_INICIADA,idprogramacion,fechahorareg,sesion); + + if (!db.Execute(sqlstr)) { // Error al recuperar los datos + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + return(enviaPeticion(idprogramacion)); +} +// ________________________________________________________________________________________________________ +// +// Función: ejecutarProcedimiento +// +// Descripción: +// Ejecuta un procedimiento programado +// Parámetros: +// - db: Objeto base de datos (operativo) +// - idprocedimiento: Identificador del procedimiento +// - ambito: Ãmbito de aplicación +// - idambito: Identificador del ámbito +// - restrambito: cadena con los identificadores de los ordenadores a los que se aplica la acción +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ + +BOOLEAN ejecutarProcedimiento(Database db,int idprocedimiento,int ambito,int idambito,char* restrambito) +{ + char msglog[LONSTD], sqlstr[LONSQL],*parametros; + Table tbl; + int procedimientoid,idcomando,lonprm; + char modulo[] = "ejecutarProcedimiento()"; + + sprintf(sqlstr,"SELECT idcomando,procedimientoid,parametros,length(parametros) as lonprm"\ + " FROM procedimientos_acciones"\ + " WHERE idprocedimiento=%d ORDER BY orden",idprocedimiento); + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + + if(tbl.ISEOF()){ + return(TRUE); // No exustde tarea + } + while(!tbl.ISEOF()){ + if(!tbl.Get("procedimientoid",procedimientoid)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(procedimientoid>0){ // Procedimiento recursivo + if(!ejecutarProcedimiento(db,procedimientoid,ambito,idambito,restrambito)){ + return(false); + } + } + else{ + if(!tbl.Get("lonprm",lonprm)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + parametros = reservaMemoria(lonprm+1); // Reserva para almacenar los parametros del procedimiento + if (parametros == NULL) { + errorLog(modulo, 3, FALSE); + return (FALSE); + } + if(!tbl.Get("parametros",parametros)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + liberaMemoria(parametros); + return (FALSE); + } + if(!tbl.Get("idcomando",idcomando)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + + if(!insertaComando(db,idcomando,parametros,idprocedimiento,ambito,idambito,restrambito)) { + + liberaMemoria(parametros); + return(false); + } + liberaMemoria(parametros); + } + tbl.MoveNext(); + } + return(TRUE); +} +// ________________________________________________________________________________________________________ +// +// Función: ejecutarTarea +// +// Descripción: +// Ejecuta una tarea programada +// Parámetros: +// - db: Objeto base de datos (operativo) +// - idtarea: Identificador de la tarea +// - idprogramacion: Identificador de la programación +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ + +BOOLEAN ejecutarTarea(Database db, int idprogramacion, int idtarea) +{ + char msglog[LONSTD], sqlstr[LONSQL]; + Table tbl; + int tareaid,ambito,idambito,idprocedimiento,lonrestrambito; + char* restrambito; + char modulo[] = "ejecutarTarea()"; + + sprintf(sqlstr,"SELECT tareas_acciones.orden,tareas_acciones.idprocedimiento,tareas_acciones.tareaid,"\ + " tareas.ambito,tareas.idambito,tareas.restrambito,length(tareas.restrambito) as lonrestrambito"\ + " FROM tareas"\ + " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"\ + " WHERE tareas_acciones.idtarea=%d ORDER BY tareas_acciones.orden",idtarea); + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + + if(tbl.ISEOF()){ + return(TRUE); // No existe tarea + } + + while(!tbl.ISEOF()){ + if(!tbl.Get("tareaid",tareaid)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(tareaid>0){ // Tarea recursiva + if(!ejecutarTarea(db,idprogramacion,tareaid)){ + return(false); + } + } + else{ + if(!tbl.Get("ambito",ambito)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("idambito",idambito)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("lonrestrambito",lonrestrambito)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + restrambito = reservaMemoria(lonrestrambito+1); + if (restrambito == NULL) { + errorLog(modulo, 3, FALSE); + return (FALSE); + } + if(!tbl.Get("restrambito",restrambito)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + liberaMemoria(restrambito); + return (FALSE); + } + liberaMemoria(restrambito); + RecopilaIpesMacs(db,ambito,idambito,restrambito); // Recopila Ipes del ámbito + if(!tbl.Get("idprocedimiento",idprocedimiento)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sesion=time(NULL); + + if(!ejecutarProcedimiento(db,idprocedimiento,ambito,idambito,restrambito)) + return(FALSE); + } + tbl.MoveNext(); + } + return(enviaPeticion(idprogramacion)); +} +// ________________________________________________________________________________________________________ +// +// Función: ejecutarTarea +// +// Descripción: +// Registra un procedimiento para un ambito concreto +// Parámetros: +// - db: Objeto base de datos (operativo) +// - idcomando: Identificador del comando +// - idprocedimiento: Identificador del procedimiento +// - ambito: Ãmbito de aplicación +// - idambito: Identificador del ámbito +// - restrambito: cadena con los identificadores de los ordenadores a los que se aplica la acción +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN insertaComando(Database db,int idcomando,char*parametros,int idprocedimiento,int ambito,int idambito,char*restrambito) +{ + char msglog[LONSTD], sqlstr[LONSQL]; + struct tm* st; + char *auxID[MAXIMOS_CLIENTES],*auxIP[MAXIMOS_CLIENTES]; + char fechahorareg[24]; + int i; + char modulo[] = "insertaComando()"; + + if(concli==0) return(TRUE); // No hay ordenadores en el ámbito + + st = tomaHora(); + sprintf(fechahorareg,"%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1, st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec); + + splitCadena(auxID,cadenaid,','); + splitCadena(auxIP,cadenaip,';'); + + for (i=0;iparametros,"nfn=envioProgramacion\r"); // Nombre de la función a ejecutar en el servidor + lon+=sprintf(ptrTrama->parametros+lon,"idp=%d\r",idprogramacion); // Configuración de los Sistemas Operativos del cliente + + if(!enviaMensaje(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,91,FALSE); + liberaMemoria(ptrTrama); + return(FALSE); + } + liberaMemoria(ptrTrama); + return(TRUE); +} +// _____________________________________________________________________________________________________________ +// +// Función: RecopilaIpesMacs +// +// Descripción : +// Recopila las IPes, las Macs y los identificadores de ordenadores de un ámbito determinado +// +// Especificaciones: +// Esta Función recibe tres parámatros: +// db : Un objeto Base de datos totalmente operativo +// ambito: Tipo de ámbito +// idambito: Identificador del ámbito +// Devuelve: +// Todas los identificadores de ordenadores , las ipes y las macs de los ordenadores que componen el ámbito +// Para ellos habrá que tener declarada tres variables globales : +// cadenaid,cadenaip y cadenamac +// _____________________________________________________________________________________________________________ + +BOOLEAN RecopilaIpesMacs(Database db,int ambito,int idambito,char *restrambito) +{ + char sqlstr[LONSQL]; + + concli=0; + /* Reserva memoria al meno para caracter nulo */ + cadenaid=(char*) reservaMemoria(1); + cadenaip=(char*) reservaMemoria(1); + cadenamac=(char*) reservaMemoria(1); + + switch(ambito){ + case AMBITO_CENTROS : + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores INNER JOIN aulas WHERE ordenadores.idaula=aulas.idaula AND idcentro=%d ORDER BY ordenadores.idaula, ordenadores.ip;",idambito); + RecorreOrdenadores(db,sqlstr); + break; + case AMBITO_GRUPOSAULAS : + sprintf(sqlstr,"SELECT idgrupo FROM grupos WHERE idgrupo=%d AND tipo=%d",idambito,AMBITO_GRUPOSAULAS); + RecorreGruposAulas(db,sqlstr); + break; + case AMBITO_AULAS : + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores WHERE idaula=%d ORDER BY ip;",idambito); + RecorreOrdenadores(db,sqlstr); + break; + case AMBITO_GRUPOSORDENADORES : + sprintf(sqlstr,"SELECT idgrupo FROM gruposordenadores WHERE idgrupo=%d",idambito); + RecorreGruposOrdenadores(db,sqlstr); + break; + case AMBITO_ORDENADORES : + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores WHERE idordenador=%d",idambito); + RecorreOrdenadores(db,sqlstr); + break; + default: // Se trata de un conjunto aleatorio de ordenadores + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores WHERE idordenador IN (%s)",restrambito); + RecorreOrdenadores(db,sqlstr); + + } + return (TRUE); +} +//________________________________________________________________________________________________________ + +BOOLEAN RecorreCentro(Database db, char* sqlstr) +{ + char msglog[LONSTD]; + Table tbl; + int idcentro; + char modulo[] = "RecorreCentro()"; + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.ISEOF()){ + if(!tbl.Get("idcentro",idcentro)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sprintf(sqlstr,"SELECT idgrupo FROM grupos WHERE idcentro=%d AND grupoid=0 AND tipo=%d",idcentro,AMBITO_GRUPOSAULAS); + RecorreGruposAulas(db,sqlstr); + sprintf(sqlstr,"SELECT idaula FROM aulas WHERE idcentro=%d AND grupoid=0",idcentro); + RecorreAulas(db,sqlstr); + } + return (TRUE); +} +//________________________________________________________________________________________________________ + +BOOLEAN RecorreGruposAulas(Database db, char* sqlstr) +{ + char msglog[LONSTD]; + Table tbl; + int idgrupo; + char modulo[] = "RecorreGruposAulas()"; + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + while(!tbl.ISEOF()){ + if(!tbl.Get("idgrupo",idgrupo)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sprintf(sqlstr,"SELECT idgrupo FROM grupos WHERE grupoid=%d AND tipo=%d",idgrupo,AMBITO_GRUPOSAULAS); + RecorreGruposAulas(db,sqlstr); + sprintf(sqlstr,"SELECT idaula FROM aulas WHERE grupoid=%d",idgrupo); + RecorreAulas(db,sqlstr); + tbl.MoveNext(); + } + return (TRUE); +} +//________________________________________________________________________________________________________ + +BOOLEAN RecorreAulas(Database db, char* sqlstr) +{ + char msglog[LONSTD]; + Table tbl; + int idaula; + char modulo[] = "RecorreAulas()"; + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + while(!tbl.ISEOF()){ + if(!tbl.Get("idaula",idaula)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sprintf(sqlstr,"SELECT idgrupo FROM gruposordenadores WHERE idaula=%d AND grupoid=0",idaula); + RecorreGruposOrdenadores(db,sqlstr); + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores WHERE idaula=%d AND grupoid=0",idaula); + RecorreOrdenadores(db,sqlstr); + tbl.MoveNext(); + } + return (TRUE); +} +//________________________________________________________________________________________________________ + +BOOLEAN RecorreGruposOrdenadores(Database db, char* sqlstr) +{ + char msglog[LONSTD]; + Table tbl; + int idgrupo; + char modulo[] = "RecorreGruposOrdenadores()"; + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + while(!tbl.ISEOF()){ + if(!tbl.Get("idgrupo",idgrupo)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sprintf(sqlstr,"SELECT idgrupo FROM gruposordenadores WHERE grupoid=%d",idgrupo); + RecorreGruposOrdenadores(db,sqlstr); + sprintf(sqlstr,"SELECT ip,mac,idordenador FROM ordenadores WHERE grupoid=%d",idgrupo); + RecorreOrdenadores(db,sqlstr); + tbl.MoveNext(); + } + return (TRUE); +} +//________________________________________________________________________________________________________ + +BOOLEAN RecorreOrdenadores(Database db, char* sqlstr) +{ + char msglog[LONSTD]; + Table tbl; + int idordenador,o,p,m,lon; + char ido[16],ip[LONIP],mac[LONMAC]; + char modulo[] = "RecorreOrdenadores()"; + + if (!db.Execute(sqlstr, tbl)) { // Error al leer + errorLog(modulo, 21, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + o=p=m=0; + while(!tbl.ISEOF()){ + if(!tbl.Get("idordenador",idordenador)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("ip",ip)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + if(!tbl.Get("mac",mac)){ + tbl.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + return (FALSE); + } + sprintf(ido,"%d",idordenador); + lon=strlen(ido); + if(lon>16) lon=16; + cadenaid=(char*) ampliaMemoria(cadenaid,o+lon+1); + memcpy(&cadenaid[o],ido,lon); + o+=lon; + cadenaid[o++]=','; + + lon=strlen(ip); + if(lon>16) lon=LONIP; + cadenaip=(char*) ampliaMemoria(cadenaip,p+lon+1); + memcpy(&cadenaip[p],ip,lon); + p+=lon; + cadenaip[p++]=';'; + + lon=strlen(mac); + if(lon>16) lon=LONMAC; + cadenamac=(char*) ampliaMemoria(cadenamac,m+lon+1); + memcpy(&cadenamac[m],mac,lon); + m+=lon; + cadenamac[m++]=';'; + + concli++; + tbl.MoveNext(); + } + if(o>0) o--; + if(p>0) p--; + if(m>0) m--; + cadenaid[o]='\0'; + cadenaip[p]='\0'; + cadenamac[m]='\0'; + + return (TRUE); +} +// ******************************************************************************************************** +// PROGRAMA PRINCIPAL (SERVICIO) +// ******************************************************************************************************** +int main(int argc, char *argv[]) +{ + int pseg; + char msglog[LONSTD]; + struct tm* st; + Database db; + char modulo[] = "main()"; + + /* Validación de parámetros de ejecución y lectura del fichero de configuración del servicio */ + + if (!validacionParametros(argc, argv, 5)) // Valida parámetros de ejecución + exit(EXIT_FAILURE); + + if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion + exit(EXIT_FAILURE); + } + + /* Bucle principal del servicio */ + + while (TRUE){ + st = tomaHora(); + pseg=65-st->tm_sec; // Calcula segundos de inactividad de la hebra + sleep(pseg); + + // Toma la hora + st = tomaHora(); + + if (!db.Open(usuario, pasguor, datasource, catalog)) { // Error de conexion + errorLog(modulo, 20, FALSE); + db.GetErrorErrStr(msglog); + errorInfo(modulo, msglog); + exit(EXIT_FAILURE); + } + buscaAccion(db,st->tm_mday,st->tm_mon+1,st->tm_year+1900,st->tm_hour,st->tm_min,st->tm_wday ); + db.Close(); // Cierra conexión + } + exit(EXIT_SUCCESS); +} + + diff --git a/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.h b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.h new file mode 100644 index 0000000..b1c429b --- /dev/null +++ b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.h @@ -0,0 +1,81 @@ +// ******************************************************************************************************** +// Servicio: ogAdmAgent +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmAgent.h +// Descripción: Este fichero implementa el servicio agente del sistema. Revisa a intervalos +// regulares la base de datos para comprobar si existen acciones programadas. +// ******************************************************************************************************** +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Database.h" +#include "ogAdmLib.h" + +// ________________________________________________________________________________________________________ +// +// Valores hexadecimales para consultas +// ________________________________________________________________________________________________________ + +WORD HEX_annos[]={0,0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000}; +WORD HEX_meses[]={0,0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800}; +int HEX_dias[]={0,0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,0x00000080,0x00000100,0x00000200, + 0x00000400,0x00000800,0x00001000,0x00002000,0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000, + 0x00100000,0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,0x40000000}; +WORD HEX_horas[]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800 }; +BYTE HEX_diasemana[]={0,0x01,0x02,0x04,0x08,0x10,0x20,0x40}; +BYTE HEX_semanas[]={0,0x01,0x02,0x04,0x08,0x10,0x20}; +WORD dias_meses[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; + +// ________________________________________________________________________________________________________ +// +// Variables globales +// ________________________________________________________________________________________________________ + +char servidoradm[LONPRM]; // Dirección IP del servidor de administración +char puerto[LONPRM]; // Puerto de comunicación +char usuario[LONPRM]; // Usuario de acceso a la base de datos +char pasguor[LONPRM]; // Password del usuario +char datasource[LONPRM]; // Dirección IP del gestor de base de datos +char catalog[LONPRM]; // Nombre de la base de datos + +int idprogramacion; +int tipoaccion,idtipoaccion; +char descriaccion[250]; +char *cadenaid; +char *cadenaip; +char *cadenamac; +int concli; +int sesion; +int idcentro; + +// ________________________________________________________________________________________________________ +// Prototipo de funciones +// ________________________________________________________________________________________________________ +BOOLEAN tomaConfiguracion(char*); +int diadelaSemana(WORD,WORD,WORD); +BOOLEAN bisiesto(WORD); +BOOLEAN buscaAccion(Database,WORD,WORD,WORD,WORD,WORD,WORD); +BOOLEAN ejecutarComando(Database,int,int ); +BOOLEAN ejecutarProcedimiento(Database,int,int,int,char*); +BOOLEAN ejecutarTarea(Database,int, int); +BOOLEAN insertaComando(Database,int,char*,int,int,int,char*); +BOOLEAN EjecutarReserva(int,Database); +BOOLEAN enviaPeticion(int); +BOOLEAN RecopilaIpesMacs(Database,int,int,char *); +BOOLEAN RecorreCentro(Database, char*); +BOOLEAN RecorreGruposAulas(Database, char*); +BOOLEAN RecorreAulas(Database, char*); +BOOLEAN RecorreGruposOrdenadores(Database, char*); +BOOLEAN RecorreOrdenadores(Database, char*); + diff --git a/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.o b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.o new file mode 100644 index 0000000..ccf5962 Binary files /dev/null and b/native/Sources/Services/ogAdmAgent/sources/ogAdmAgent.o differ diff --git a/native/Sources/Services/ogAdmRepoAux b/native/Sources/Services/ogAdmRepoAux new file mode 100755 index 0000000..ede2bea --- /dev/null +++ b/native/Sources/Services/ogAdmRepoAux @@ -0,0 +1,285 @@ +#!/bin/bash +PARM=`cat` +#PARM=$@ + + +#TODO: ticket 379 +#buscar parametro de identificador de operacion. +#usar parametro de identificacion para anexarlo al nombre de log +#Comprobar si la variable está seteas. +#Si no lo está setearla. +#Si esta seteada (en progreso) salir. + + +TIME=$SECONDS + +BASEDIR=/opt/opengnsys +PATH=$PATH:$BASEDIR/bin +REPONAME=ogAdmRepo +REPODIR="$BASEDIR/images/" + +# Para las sincronizadas +# BACKUP: Define si se realiza copia de seguridad al crear una imagen (true|false). +# IMGFS: Sistema de ficheros al crear las sincronizadas tipo archivo (EXT4|BTRFS). +[ -z $OGENGINECONFIGURATE ] && source $BASEDIR/client/etc/engine.cfg +# FS segun la configuracion y la version del kernel. ext4 para < 3.7, para >= BTRFS +KERNEL=$(file -bkr /opt/opengnsys/tftpboot/ogclient/ogvmlinuz |awk '/Linux/ {for(i=1;i<=NF;i++) if($i~/version/) {v=$(i+1);printf("%d",v);sub(/[0-9]*\./,"",v);printf(".%02d",v)}}') +[ $KERNEL \< 3.07 ] && IMGFS="EXT4" || IMGFS=${IMGFS:-"BTRFS"} + +# Añade registro de incidencias. +function echolog () { + logger --tag $0 --priority local0.info "$*" + echo "$*" +} + +function mountImage () { + #@param 1 image_file + #@param 2 mount_dir + #@param 3 openciones mount + [ "$3" != "" ] && OPTMOUNT=" -o $3 " + # Si está montado nada que hacer + df |grep "$2$" 2>&1 >/dev/null && return 0 + # FS de la imagen segun el contenido del archivo .img + if file "$1" |grep -i -e " ext4 filesystem " 2>&1 > /dev/null ; then + echolog "mount $OPTMOUNT -t ext4 $1 $2" + mount $OPTMOUNT -t ext4 $1 $2 + else + echolog "mount $OPTMOUNT -o compress=lzo $1 $2" + mount $OPTMOUNT -o compress=lzo "$1" "$2" + fi + # Si esta montado da error 32, lo damos como bueno + RETVAL=$? + [ $RETVAL -eq 32 ] && RETVAL=0 + return $RETVAL +} + + +PARM1=$(echo $PARM | cut -f1 -d" ") +PARM2=$(echo $PARM | cut -f2 -d" ") +PARM3=$(echo $PARM | cut -f3 -d" ") +PARM4=$(echo $PARM | cut -f4 -d" ") + +# Determinamos el tipo de sistema de fichero de las imagenes segun el kernel que tenga + + +case "$PARM1" in + START_MULTICAST) + #1 START_MULTICAST + #2 fichero a enviar + #3 opciones de multicast + FILE="$PARM2" + MCASTOPT="$PARM3" + echolog "Ejecutar $(which sendFileMcast) $FILE $MCASTOPT" + sendFileMcast $FILE $MCASTOPT |logger --tag $0 --priority local0.info + case $? in + 1) echolog "Parametros insuficientes" + exit 1 ;; + 2) echolog "Fichero no accesible" + exit 2 ;; + 3) echolog "Sesion multicast no valida" + exit 3 ;; + esac + ;; + CREATE_IMAGE) + # Creamos/Redimensionamos el fichero de imagen y lo montamos para que se pueda escribir sobre el + #1 CREATE_IMAGE + #2 nombre imagen + #3 tipo de imagen [ img | diff ] + #4 tamaño imagen + LOOPDEVICE=$(losetup -f) + DIRMOUNT="$REPODIR/mount/$PARM2" + if [ "$PARM3" == "img" ] ; then + IMGEXT="img" + else + IMGEXT="img.diff" + DIRMOUNT="$DIRMOUNT.diff" + fi + IMGFILE="$REPODIR/$PARM2.$IMGEXT" + IMGDIR="$(dirname $IMGFILE)" + [ -d $IMGDIR ] || mkdir -p $IMGDIR + mkdir -p "$DIRMOUNT" + + LOCKFILE="$IMGFILE.lock" + + SIZEREQUIRED="$PARM4" + + # Si existe la imagen hacemos copia de seguridad y la redimesionamos + if [ -f "$IMGFILE" ]; then + echolog "La imagen $IMGFILE ya existe." + # TODO modificar ogGetImageSize + IMGSIZE=$(ls -l --block-size=1024 $IMGFILE| cut -f5 -d" ") + + if [ "$BACKUP" == "true" -o "$BACKUP" == "TRUE" -o $IMGSIZE -lt $SIZEREQUIRED ]; then + # Si la imagen esta montada la desmonto + if [ -r "$DIRMOUNT/ogimg.info" ]; then + echolog "umount $DIRMOUNT" + umount "$DIRMOUNT" + [ $? -ne 0 ] && echolog "Error: No podemos desmontar la imagen para hacer copia de seguridad o redimensionar" && exit 1 + fi + fi + + # Copia de seguridad de la imagen + if [ "$BACKUP" == "true" -o "$BACKUP" == "TRUE" ]; then + echolog "Copia de seguridad de la imagen anterior" + echolog "cp $IMGFILE $IMGFILE.ant" + cp "$IMGFILE" "$IMGFILE.ant" + echolog mv -f "$IMGFILE.torrent" "$IMGFILE.torrent.ant" 2>/dev/null + mv -f "$IMGFILE.torrent" "$IMGFILE.torrent.ant" 2>/dev/null + fi + + # Redimensionamos la imagen al tamaño necesario + if [ $IMGSIZE -lt $SIZEREQUIRED ];then + echolog "Redimensionamos la imagen $IMGFILE al tamaño necesario: $SIZEREQUIRED" + echolog "truncate --size=\">$SIZEREQUIRED\"k $IMGFILE" + truncate --size=">$SIZEREQUIRED"k $IMGFILE 2>&1 |logger --tag $0 --priority local0.info + # FS de la imagen segun el contenido del archivo .img + if file "$IMGFILE" |grep -i -e " ext4 filesystem " 2>&1 > /dev/null ; then + losetup $LOOPDEVICE "$IMGFILE" + echolog "resize2fs -f $LOOPDEVICE" + resize2fs -f $LOOPDEVICE |logger --tag $0 --priority local0.info + else + mount -o compress=lzo "$IMGFILE" "$DIRMOUNT" + echolog "btrfs filesystem resize max $DIRMOUNT" + btrfs filesystem resize max "$DIRMOUNT" 2>&1 |logger --tag $0 --priority local0.info + fi + fi + + + # Si no existe la imagen creamos el fichero. + else + echolog "Creamos la imagen $IMGFILE al tamaño necesario: $SIZEREQUIRED" + touch "$IMGFILE" + echolog "truncate --size=\">$SIZEREQUIRED\"k $IMGFILE" + truncate --size=">$SIZEREQUIRED"k $IMGFILE 2>&1 |logger --tag $0 --priority local0.info + #Formateamos imagen + echo losetup $LOOPDEVICE "$IMGFILE" + losetup $LOOPDEVICE "$IMGFILE" + if [ $IMGFS == "EXT4" ] ; then + echolog " mkfs.ext4 -i 4096 -b 4096 -L ${PARM2##*\/} $LOOPDEVICE" + mkfs.ext4 -i 4096 -b 4096 -L ${PARM2##*\/} $LOOPDEVICE + else + echolog mkfs.btrfs -L ${PARM2##*\/} $LOOPDEVICE + mkfs.btrfs -L ${PARM2##*\/} $LOOPDEVICE #&> $OGLOGCOMMAND + fi + fi + # Montamos la imagen. + mountImage "$IMGFILE" "$DIRMOUNT" + if [ $? -ne 0 ]; then + rmdir "$DIRMOUNT" + echolog "Error al crear/redimensionar la imagen" + exit 1 + fi + + #touch "$DIRMOUNT/ogimg.info" + echo "mounted"> "$LOCKFILE" + TIME2=$[SECONDS-TIME] + echolog "Fin creación/redimension de la imagen: $[TIME2/60]m $[TIME2%60]s" + # Si existe dispositivo loop lo borramos. + [ $LOOPDEVICE ] && losetup -a| grep $LOOPDEVICE &> /dev/null && losetup -d $LOOPDEVICE + # TODO: comprobar que no se quede el losetup bloqueado. + + ;; + MOUNT_IMAGE) + # Montamos el fichero imagen para que se pueda + #1 MOUNT_IMAGE + #2 nombre imagen + #3 tipo de imagen [ img | diff ] + DIRMOUNT="$REPODIR""mount/$PARM2" + if [ "$PARM3" == "img" ] ; then + IMGEXT="img" + else + IMGEXT="img.diff" + DIRMOUNT="$DIRMOUNT.diff" + fi + IMGFILE="$REPODIR/$PARM2.$IMGEXT" + echolog "Montamos la imagen $IMGFILE " + mkdir -p "$DIRMOUNT" + mountImage "$IMGFILE" "$DIRMOUNT" ro || (echolog "Error al montar la imagen"; exit 1) + ;; + UMOUNT_IMAGE) + # Desmontamos el fichero imagen. + # Si el directorio esta ocupado no se desmontará + #1 UMOUNT_IMAGE + #2 nombre imagen + #3 tipo de imagen [ img | diff ] + IMGTYPE="$PARM3" + DIRMOUNT="$REPODIR/mount/$PARM2" + if [ "$IMGTYPE" == "img" ]; then + IMGEXT="img" + else + DIRMOUNT="$DIRMOUNT.$IMGTYPE" + IMGEXT="img.diff" + fi + LOCKFILE="$REPODIR/$PARM2.$IMGEXT.lock" + echolog "Desmontamos la imagen $PARM2 $PARM3 " + umount $DIRMOUNT + rmdir $DIRMOUNT + [ -f $LOCKFILE ] && sed -i s/mounted//g $LOCKFILE + + ;; + REDUCE_IMAGE) + # Reduce el archivo de la imagen a tamaño datos + 500M + #1 REDUCE_IMAGE + #2 Nombre Imagen + #3 Tipo de imagen [ img |diff ] + DIRMOUNT="${REPODIR}mount/${PARM2}" + if [ "$PARM3" == "img" ] ; then + IMGEXT="img" + else + IMGEXT="img.diff" + DIRMOUNT="$DIRMOUNT.diff" + fi + IMGFILE="$REPODIR$PARM2.$IMGEXT" + LOCKFILE="$IMGFILE.lock" + [ ! -f $IMGFILE ] && echolog "Imagen $IMGFILE no existe" && exit 1 + + # Para imagenes EXT4 reduzco, para BTRFS solo desmonto. + if file $IMGFILE |grep -i -e " ext4 filesystem " 2>&1 > /dev/null ; then + + [ -d $DIRMOUNT ] || mkdir $DIRMOUNT + mountImage "$IMGFILE" "$DIRMOUNT" || (echolog "Error al montar la imagen $IMGFILE"; exit 1) + + + # Si el espacio libre menor que 200Mb desmontamos la imagen y nos salimos + AVAILABLE=$(df -k|grep $DIRMOUNT|awk '{print $4}') + if [ $AVAILABLE -lt 200000 ]; then + echolog "reducir imagen REPO $PARM2 $IMGEXT. tamaño minimo, nada que hacer" + umount $DIRMOUNT || (echolog "Error al desmontar la imagen $IMGFILE"; exit 1) + else + + # Calculamos la diferencia entre el tamaño interno y externo + EXTSIZE=$(ls -l --block-size=1024 $IMGFILE | cut -f5 -d" ") + INTSIZE=$(df -k|grep "$DIRMOUNT"|awk '{print $2}') + let EDGESIZE=$EXTSIZE-$INTSIZE + + echolog "reducir imagen REPO $PARM2 $IMGEXT, tamaño final: $ENDSIZE" + umount $DIRMOUNT + LOOPDEVICE=$(losetup -f) + losetup $LOOPDEVICE "$IMGFILE" + + # Redimensiono sistema de ficheros + echolog "resize2fs -fpM $LOOPDEVICE " + resize2fs -fpM $LOOPDEVICE # 2>&1 |logger --tag $0 --priority local0.info + mountImage "$IMGFILE" "$DIRMOUNT" + # Calculamos el tamaño final del archivo + INTSIZE=$(df -k|grep "$DIRMOUNT"|awk '{print $2}') + let EXTSIZE=$INTSIZE+$EDGESIZE + umount $DIRMOUNT || (echolog "Error al desmontar la imagen $IMGFILE"; exit 1) + # Si existe dispositivo loop lo borramos. + [ $LOOPDEVICE ] && losetup -a| grep $LOOPDEVICE &> /dev/null && losetup -d $LOOPDEVICE + # Corto el archivo al tamaño del sistema de ficheros + echo "truncate --size=\"$EXTSIZE\"k $IMGFILE" + echolog "truncate --size=\"$EXTSIZE\"k $IMGFILE" + truncate --size="$EXTSIZE"k $IMGFILE + fi + else + umount $DIRMOUNT || (echolog "Error al desmontar la imagen $IMGFILE"; exit 1) + fi + rmdir $DIRMOUNT + echo "reduced" >$LOCKFILE + + ;; + default) + echolog "Solicitud con parametros \"$PARM\" no realizada, no registrada o con errores" + ;; +esac diff --git a/native/Sources/Services/ogAdmServer/Makefile b/native/Sources/Services/ogAdmServer/Makefile new file mode 100644 index 0000000..0c3360e --- /dev/null +++ b/native/Sources/Services/ogAdmServer/Makefile @@ -0,0 +1,38 @@ +# makefile + +# Nombre del proyecto +PROYECTO := ogAdmServer + +# Directorio de instalación +INSTALL_DIR := /opt/opengnsys + +# Opciones de compilacion +CFLAGS := $(shell mysql_config --cflags) +CFLAGS += -g -Wall -I../../Includes + +# Opciones de linkado +LDFLAGS := -Wl,--no-as-needed $(shell mysql_config --libs) -lev -ljansson -ldbi + +# Ficheros objetos +OBJS := sources/ogAdmServer.o sources/dbi.o + + +all: $(PROYECTO) + +$(PROYECTO): $(OBJS) + gcc $(LDFLAGS) $(CFLAGS) $(OBJS) -o $(PROYECTO) + +install: $(PROYECTO) + cp $(PROYECTO) $(INSTALL_DIR)/sbin + cp $(PROYECTO).cfg $(INSTALL_DIR)/etc + +clean: + rm -f $(PROYECTO) $(OBJS) + +uninstall: clean + rm -f /usr/local/sbin/$(PROYECTO) /usr/local/etc/$(PROYECTO).cfg + +sources/%.o: sources/%.c + gcc $(CFLAGS) -c -o"$@" "$<" + + diff --git a/native/Sources/Services/ogAdmServer/Sources-Services-.txt b/native/Sources/Services/ogAdmServer/Sources-Services-.txt new file mode 100644 index 0000000..8ed387e --- /dev/null +++ b/native/Sources/Services/ogAdmServer/Sources-Services-.txt @@ -0,0 +1 @@ +Sources/Services/ogAdmServer \ No newline at end of file diff --git a/native/Sources/Services/ogAdmServer/ogAdmServer.cfg b/native/Sources/Services/ogAdmServer/ogAdmServer.cfg new file mode 100644 index 0000000..790b233 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/ogAdmServer.cfg @@ -0,0 +1,8 @@ +ServidorAdm=SERVERIP +PUERTO=2008 +USUARIO=DBUSER +PASSWORD=DBPASSWORD +datasource=localhost +CATALOG=DATABASE +INTERFACE=eth0 +APITOKEN=REPOKEY diff --git a/native/Sources/Services/ogAdmServer/sources/dbi.c b/native/Sources/Services/ogAdmServer/sources/dbi.c new file mode 100644 index 0000000..cc5c5b5 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/sources/dbi.c @@ -0,0 +1,37 @@ +#include "dbi.h" + +struct og_dbi *og_dbi_open(struct og_dbi_config *config) +{ + struct og_dbi *dbi; + + dbi = (struct og_dbi *)malloc(sizeof(struct og_dbi)); + if (!dbi) + return NULL; + + dbi_initialize_r(NULL, &dbi->inst); + dbi->conn = dbi_conn_new_r("mysql", dbi->inst); + if (!dbi->conn) { + free(dbi); + return NULL; + } + + dbi_conn_set_option(dbi->conn, "host", config->host); + dbi_conn_set_option(dbi->conn, "username", config->user); + dbi_conn_set_option(dbi->conn, "password", config->passwd); + dbi_conn_set_option(dbi->conn, "dbname", config->database); + dbi_conn_set_option(dbi->conn, "encoding", "UTF-8"); + + if (dbi_conn_connect(dbi->conn) < 0) { + free(dbi); + return NULL; + } + + return dbi; +} + +void og_dbi_close(struct og_dbi *dbi) +{ + dbi_conn_close(dbi->conn); + dbi_shutdown_r(dbi->inst); + free(dbi); +} diff --git a/native/Sources/Services/ogAdmServer/sources/dbi.h b/native/Sources/Services/ogAdmServer/sources/dbi.h new file mode 100644 index 0000000..bbb91d7 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/sources/dbi.h @@ -0,0 +1,22 @@ +#ifndef __OG_DBI +#define __OG_DBI + +#include + +struct og_dbi_config { + const char *user; + const char *passwd; + const char *host; + const char *database; +}; + +struct og_dbi { + dbi_conn conn; + dbi_inst inst; +}; + +struct og_dbi *og_dbi_open(struct og_dbi_config *config); +void og_dbi_close(struct og_dbi *db); +#define OG_DB_IP_MAXLEN 15 + +#endif diff --git a/native/Sources/Services/ogAdmServer/sources/dbi.o b/native/Sources/Services/ogAdmServer/sources/dbi.o new file mode 100644 index 0000000..f42f644 Binary files /dev/null and b/native/Sources/Services/ogAdmServer/sources/dbi.o differ diff --git a/native/Sources/Services/ogAdmServer/sources/ogAdmServer.c b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.c new file mode 100644 index 0000000..4a76c03 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.c @@ -0,0 +1,4961 @@ +// ******************************************************************************************************* +// Servicio: ogAdmServer +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmServer.cpp +// Descripción :Este fichero implementa el servicio de administración general del sistema +// ******************************************************************************************************* +#include "ogAdmServer.h" +#include "ogAdmLib.c" +#include "dbi.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static char usuario[LONPRM]; // Usuario de acceso a la base de datos +static char pasguor[LONPRM]; // Password del usuario +static char datasource[LONPRM]; // Dirección IP del gestor de base de datos +static char catalog[LONPRM]; // Nombre de la base de datos +static char interface[LONPRM]; // Interface name +static char auth_token[LONPRM]; // API token + +static struct og_dbi_config dbi_config = { + .user = usuario, + .passwd = pasguor, + .host = datasource, + .database = catalog, +}; + +//________________________________________________________________________________________________________ +// Función: tomaConfiguracion +// +// Descripción: +// Lee el fichero de configuración del servicio +// Parámetros: +// filecfg : Ruta completa al fichero de configuración +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +static bool tomaConfiguracion(const char *filecfg) +{ + char buf[1024], *line; + char *key, *value; + FILE *fcfg; + + if (filecfg == NULL || strlen(filecfg) == 0) { + syslog(LOG_ERR, "No configuration file has been specified\n"); + return false; + } + + fcfg = fopen(filecfg, "rt"); + if (fcfg == NULL) { + syslog(LOG_ERR, "Cannot open configuration file `%s'\n", + filecfg); + return false; + } + + servidoradm[0] = '\0'; //inicializar variables globales + + line = fgets(buf, sizeof(buf), fcfg); + while (line != NULL) { + const char *delim = "="; + + line[strlen(line) - 1] = '\0'; + + key = strtok(line, delim); + value = strtok(NULL, delim); + + if (!strcmp(StrToUpper(key), "SERVIDORADM")) + snprintf(servidoradm, sizeof(servidoradm), "%s", value); + else if (!strcmp(StrToUpper(key), "PUERTO")) + snprintf(puerto, sizeof(puerto), "%s", value); + else if (!strcmp(StrToUpper(key), "USUARIO")) + snprintf(usuario, sizeof(usuario), "%s", value); + else if (!strcmp(StrToUpper(key), "PASSWORD")) + snprintf(pasguor, sizeof(pasguor), "%s", value); + else if (!strcmp(StrToUpper(key), "DATASOURCE")) + snprintf(datasource, sizeof(datasource), "%s", value); + else if (!strcmp(StrToUpper(key), "CATALOG")) + snprintf(catalog, sizeof(catalog), "%s", value); + else if (!strcmp(StrToUpper(key), "INTERFACE")) + snprintf(interface, sizeof(interface), "%s", value); + else if (!strcmp(StrToUpper(key), "APITOKEN")) + snprintf(auth_token, sizeof(auth_token), "%s", value); + + line = fgets(buf, sizeof(buf), fcfg); + } + + fclose(fcfg); + + if (!servidoradm[0]) { + syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n"); + return false; + } + if (!puerto[0]) { + syslog(LOG_ERR, "Missing PUERTO in configuration file\n"); + return false; + } + if (!usuario[0]) { + syslog(LOG_ERR, "Missing USUARIO in configuration file\n"); + return false; + } + if (!pasguor[0]) { + syslog(LOG_ERR, "Missing PASSWORD in configuration file\n"); + return false; + } + if (!datasource[0]) { + syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n"); + return false; + } + if (!catalog[0]) { + syslog(LOG_ERR, "Missing CATALOG in configuration file\n"); + return false; + } + if (!interface[0]) + syslog(LOG_ERR, "Missing INTERFACE in configuration file\n"); + + return true; +} + +enum og_client_state { + OG_CLIENT_RECEIVING_HEADER = 0, + OG_CLIENT_RECEIVING_PAYLOAD, + OG_CLIENT_PROCESSING_REQUEST, +}; + +#define OG_MSG_REQUEST_MAXLEN 16384 + +/* Shut down connection if there is no complete message after 10 seconds. */ +#define OG_CLIENT_TIMEOUT 10 + +struct og_client { + struct ev_io io; + struct ev_timer timer; + struct sockaddr_in addr; + enum og_client_state state; + char buf[OG_MSG_REQUEST_MAXLEN]; + unsigned int buf_len; + unsigned int msg_len; + int keepalive_idx; + bool rest; + int content_length; + char auth_token[64]; +}; + +static inline int og_client_socket(const struct og_client *cli) +{ + return cli->io.fd; +} + +// ________________________________________________________________________________________________________ +// Función: clienteDisponible +// +// Descripción: +// Comprueba la disponibilidad del cliente para recibir comandos interactivos +// Parametros: +// - ip : La ip del cliente a buscar +// - idx: (Salida) Indice que ocupa el cliente, de estar ya registrado +// Devuelve: +// true: Si el cliente está disponible +// false: En caso contrario +// ________________________________________________________________________________________________________ +bool clienteDisponible(char *ip, int* idx) +{ + int estado; + + if (clienteExistente(ip, idx)) { + estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado + if (estado == 0) + return false; + + estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado + if (estado == 0) + return false; + + estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión + if (estado == 0) + return false; + + return true; // En caso contrario el cliente está disponible + } + return false; // Cliente no está registrado en el sistema +} +// ________________________________________________________________________________________________________ +// Función: clienteExistente +// +// Descripción: +// Comprueba si el cliente está registrado en la tabla de socket del sistema +// Parametros: +// - ip : La ip del cliente a buscar +// - idx:(Salida) Indice que ocupa el cliente, de estar ya registrado +// Devuelve: +// true: Si el cliente está registrado +// false: En caso contrario +// ________________________________________________________________________________________________________ +bool clienteExistente(char *ip, int* idx) +{ + int i; + for (i = 0; i < MAXIMOS_CLIENTES; i++) { + if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena + *idx = i; + return true; + } + } + return false; +} +// ________________________________________________________________________________________________________ +// Función: hayHueco +// +// Descripción: +// Esta función devuelve true o false dependiendo de que haya hueco en la tabla de sockets para un nuevo cliente. +// Parametros: +// - idx: Primer indice libre que se podrn utilizar +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool hayHueco(int *idx) +{ + int i; + + for (i = 0; i < MAXIMOS_CLIENTES; i++) { + if (strncmp(tbsockets[i].ip, "\0", 1) == 0) { // Hay un hueco + *idx = i; + return true; + } + } + return false; +} +// ________________________________________________________________________________________________________ +// Función: InclusionClienteWin +// +// Descripción: +// Esta función incorpora el socket de un nuevo cliente Windows o Linux a la tabla de clientes +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool InclusionClienteWinLnx(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + int res,idordenador,lon; + char nombreordenador[LONFIL]; + + res = procesoInclusionClienteWinLnx(socket_c, ptrTrama, &idordenador, + nombreordenador); + + // Prepara la trama de respuesta + + initParametros(ptrTrama,0); + ptrTrama->tipo=MSG_RESPUESTA; + lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionClienteWinLnx\r"); + lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador); + lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador); + lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", res); + + if (!mandaTrama(&socket_c, ptrTrama)) { + syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + return false; + } + return true; +} +// ________________________________________________________________________________________________________ +// Función: procesoInclusionClienteWinLnx +// +// Descripción: +// Implementa el proceso de inclusión en el sistema del Cliente Windows o Linux +// Parámetros de entrada: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Parámetros de salida: +// - ido: Identificador del ordenador +// - nombreordenador: Nombre del ordenador +// Devuelve: +// Código del error producido en caso de ocurrir algún error, 0 si el proceso es correcto +// ________________________________________________________________________________________________________ +bool procesoInclusionClienteWinLnx(int socket_c, TRAMA *ptrTrama, int *idordenador, char *nombreordenador) + { + struct og_dbi *dbi; + const char *msglog; + dbi_result result; + char *iph; + + // Toma parámetros + iph = copiaParametro("iph",ptrTrama); // Toma ip + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + goto err_dbi_open; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT idordenador,nombreordenador FROM ordenadores " + " WHERE ordenadores.ip = '%s'", iph); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + goto err_query_fail; + } + + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, "client does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + goto err_query_fail; + } + + syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph); + + *idordenador = dbi_result_get_uint(result, "idordenador"); + nombreordenador = (char *)dbi_result_get_string(result, "nombreordenador"); + + dbi_result_free(result); + og_dbi_close(dbi); + + if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets + liberaMemoria(iph); + syslog(LOG_ERR, "client table is full\n"); + return false; + } + liberaMemoria(iph); + return true; + +err_query_fail: + og_dbi_close(dbi); +err_dbi_open: + liberaMemoria(iph); + return false; +} +// ________________________________________________________________________________________________________ +// Función: InclusionCliente +// +// Descripción: +// Esta función incorpora el socket de un nuevo cliente a la tabla de clientes y le devuelve alguna de sus propiedades: +// nombre, identificador, tamaño de la caché , etc ... +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool InclusionCliente(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + + if (!procesoInclusionCliente(cli, ptrTrama)) { + initParametros(ptrTrama,0); + strcpy(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\rres=0\r"); + if (!mandaTrama(&socket_c, ptrTrama)) { + syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + return false; + } + } + return true; +} +// ________________________________________________________________________________________________________ +// Función: procesoInclusionCliente +// +// Descripción: +// Implementa el proceso de inclusión en el sistema del Cliente +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool procesoInclusionCliente(struct og_client *cli, TRAMA *ptrTrama) +{ + int socket_c = og_client_socket(cli); + const char *msglog, *str; + struct og_dbi *dbi; + dbi_result result; + + char *iph, *cfg; + char nombreordenador[LONFIL]; + int lon, resul, idordenador, cache, idproautoexec, idaula, idcentro; + + // Toma parámetros + iph = copiaParametro("iph",ptrTrama); // Toma ip + cfg = copiaParametro("cfg",ptrTrama); // Toma configuracion + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + goto err_dbi_open; + } + + // Recupera los datos del cliente + result = dbi_conn_queryf(dbi->conn, + "SELECT ordenadores.*,aulas.idaula,centros.idcentro FROM ordenadores " + " INNER JOIN aulas ON aulas.idaula=ordenadores.idaula" + " INNER JOIN centros ON centros.idcentro=aulas.idcentro" + " WHERE ordenadores.ip = '%s'", iph); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + goto err_query_fail; + } + + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, "client does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + goto err_query_fail; + } + + syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph); + + idordenador = dbi_result_get_uint(result, "idordenador"); + str = (char *)dbi_result_get_string(result, "nombreordenador"); + sprintf(nombreordenador, "%s", str); + cache = dbi_result_get_uint(result, "cache"); + idproautoexec = dbi_result_get_uint(result, "idproautoexec"); + idaula = dbi_result_get_uint(result, "idaula"); + idcentro = dbi_result_get_uint(result, "idcentro"); + dbi_result_free(result); + + resul = actualizaConfiguracion(dbi, cfg, idordenador); // Actualiza la configuración del ordenador + liberaMemoria(cfg); + og_dbi_close(dbi); + + if (!resul) { + liberaMemoria(iph); + syslog(LOG_ERR, "Cannot add client to database\n"); + return false; + } + + if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets + liberaMemoria(iph); + syslog(LOG_ERR, "client table is full\n"); + return false; + } + + /*------------------------------------------------------------------------------------------------------------------------------ + Prepara la trama de respuesta + -------------------------------------------------------------------------------------------------------------------------------*/ + initParametros(ptrTrama,0); + ptrTrama->tipo=MSG_RESPUESTA; + lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\r"); + lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador); + lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador); + lon += sprintf(ptrTrama->parametros + lon, "che=%d\r", cache); + lon += sprintf(ptrTrama->parametros + lon, "exe=%d\r", idproautoexec); + lon += sprintf(ptrTrama->parametros + lon, "ida=%d\r", idaula); + lon += sprintf(ptrTrama->parametros + lon, "idc=%d\r", idcentro); + lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", 1); // Confirmación proceso correcto + + if (!mandaTrama(&socket_c, ptrTrama)) { + syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + return false; + } + liberaMemoria(iph); + return true; + +err_query_fail: + og_dbi_close(dbi); +err_dbi_open: + liberaMemoria(iph); + liberaMemoria(cfg); + return false; +} +// ________________________________________________________________________________________________________ +// Función: actualizaConfiguracion +// +// Descripción: +// Esta función actualiza la base de datos con la configuracion de particiones de un cliente +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - cfg: cadena con una Configuración +// - ido: Identificador del ordenador cliente +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// Especificaciones: +// Los parametros de la configuración son: +// par= Número de partición +// cpt= Codigo o tipo de partición +// sfi= Sistema de ficheros que está implementado en la partición +// soi= Nombre del sistema de ficheros instalado en la partición +// tam= Tamaño de la partición +// ________________________________________________________________________________________________________ +bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido) +{ + int lon, p, c,i, dato, swu, idsoi, idsfi,k; + char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD]; + char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración. + dbi_result result, result_update; + const char *msglog; + + lon = 0; + p = splitCadena(ptrPar, cfg, '\n'); + for (i = 0; i < p; i++) { + c = splitCadena(ptrCfg, ptrPar[i], '\t'); + + // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD. + if (i == 0 && c == 1) { + splitCadena(ptrDual, ptrCfg[0], '='); + ser = ptrDual[1]; + if (strlen(ser) > 0) { + // Solo actualizar si número de serie no existía. + result = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores SET numserie='%s'" + " WHERE idordenador=%d AND numserie IS NULL", + ser, ido); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + } + continue; + } + + // Distribución de particionado. + disk = par = cpt = sfi = soi = tam = uso = NULL; + + splitCadena(ptrDual, ptrCfg[0], '='); + disk = ptrDual[1]; // Número de disco + + splitCadena(ptrDual, ptrCfg[1], '='); + par = ptrDual[1]; // Número de partición + + k=splitCadena(ptrDual, ptrCfg[2], '='); + if(k==2){ + cpt = ptrDual[1]; // Código de partición + }else{ + cpt = (char*)"0"; + } + + k=splitCadena(ptrDual, ptrCfg[3], '='); + if(k==2){ + sfi = ptrDual[1]; // Sistema de ficheros + /* Comprueba existencia del s0xistema de ficheros instalado */ + idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero"); + } + else + idsfi=0; + + k=splitCadena(ptrDual, ptrCfg[4], '='); + if(k==2){ // Sistema operativo detecdtado + soi = ptrDual[1]; // Nombre del S.O. instalado + /* Comprueba existencia del sistema operativo instalado */ + idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso"); + } + else + idsoi=0; + + splitCadena(ptrDual, ptrCfg[5], '='); + tam = ptrDual[1]; // Tamaño de la partición + + splitCadena(ptrDual, ptrCfg[6], '='); + uso = ptrDual[1]; // Porcentaje de uso del S.F. + + lon += sprintf(tbPar + lon, "(%s, %s),", disk, par); + + result = dbi_conn_queryf(dbi->conn, + "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso" + " FROM ordenadores_particiones" + " WHERE idordenador=%d AND numdisk=%s AND numpar=%s", + ido, disk, par); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + result_update = dbi_conn_queryf(dbi->conn, + "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)" + " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)", + ido, disk, par, cpt, tam, uso, idsfi, idsoi); + if (!result_update) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result_update); + + } else { // Existe el registro + swu = true; // Se supone que algún dato ha cambiado + + dato = dbi_result_get_ulonglong(result, "tamano"); + if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado + dato = dbi_result_get_uint(result, "idsistemafichero"); + if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado + dato = dbi_result_get_uint(result, "idnombreso"); + if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado + swu = false; // Todos los parámetros de la partición son iguales, no se actualiza + } + } + } + if (swu) { // Hay que actualizar los parámetros de la partición + result_update = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores_particiones SET " + " codpar=0x%s," + " tamano=%s," + " uso=%s," + " idsistemafichero=%d," + " idnombreso=%d," + " idimagen=0," + " idperfilsoft=0," + " fechadespliegue=NULL" + " WHERE idordenador=%d AND numdisk=%s AND numpar=%s", + cpt, tam, uso, idsfi, idsoi, ido, disk, par); + } else { // Actualizar porcentaje de uso. + result_update = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores_particiones SET " + " codpar=0x%s," + " uso=%s" + " WHERE idordenador=%d AND numdisk=%s AND numpar=%s", + cpt, uso, ido, disk, par); + } + if (!result_update) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + + dbi_result_free(result_update); + } + dbi_result_free(result); + } + lon += sprintf(tbPar + lon, "(0,0)"); + // Eliminar particiones almacenadas que ya no existen + result_update = dbi_conn_queryf(dbi->conn, + "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)", + ido, tbPar); + if (!result_update) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result_update); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: checkDato +// +// Descripción: +// Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en +// cualquier caso el identificador del registro existenet o del insertado +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - dato: Dato +// - tabla: Nombre de la tabla +// - nomdato: Nombre del dato en la tabla +// - nomidentificador: Nombre del identificador en la tabla +// Devuelve: +// El identificador del registro existente o el del insertado +// +// Especificaciones: +// En caso de producirse algún error se devuelve el valor 0 +// ________________________________________________________________________________________________________ + +int checkDato(struct og_dbi *dbi, char *dato, const char *tabla, + const char *nomdato, const char *nomidentificador) +{ + const char *msglog; + int identificador; + dbi_result result; + + if (strlen(dato) == 0) + return (0); // EL dato no tiene valor + result = dbi_conn_queryf(dbi->conn, + "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador, + tabla, nomdato, dato); + + // Ejecuta consulta + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return (0); + } + if (!dbi_result_next_row(result)) { // Software NO existente + dbi_result_free(result); + + result = dbi_conn_queryf(dbi->conn, + "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return (0); + } + // Recupera el identificador del software + identificador = dbi_conn_sequence_last(dbi->conn, NULL); + } else { + identificador = dbi_result_get_uint(result, nomidentificador); + } + dbi_result_free(result); + + return (identificador); +} +// ________________________________________________________________________________________________________ +// Función: registraCliente +// +// Descripción: +// Incluye al cliente en la tabla de sokets +// Parámetros: +// - iph: Dirección ip del cliente +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool registraCliente(char *iph) +{ + int idx; + + if (!clienteExistente(iph, &idx)) { // Si no existe la IP ... + if (!hayHueco(&idx)) { // Busca hueco para el nuevo cliente + return false; // No hay huecos + } + } + strcpy(tbsockets[idx].ip, iph); // Copia IP + strcpy(tbsockets[idx].estado, CLIENTE_INICIANDO); // Actualiza el estado del cliente + return true; +} +// ________________________________________________________________________________________________________ +// Función: AutoexecCliente +// +// Descripción: +// Envía archivo de autoexec al cliente +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool AutoexecCliente(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + int lon; + char *iph, *exe; + FILE *fileexe; + char fileautoexec[LONPRM]; + char parametros[LONGITUD_PARAMETROS]; + struct og_dbi *dbi; + + iph = copiaParametro("iph",ptrTrama); // Toma dirección IP del cliente + exe = copiaParametro("exe",ptrTrama); // Toma identificador del procedimiento inicial + + sprintf(fileautoexec, "/tmp/Sautoexec-%s", iph); + liberaMemoria(iph); + fileexe = fopen(fileautoexec, "wb"); // Abre fichero de script + if (fileexe == NULL) { + syslog(LOG_ERR, "cannot create temporary file\n"); + return false; + } + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + initParametros(ptrTrama,0); + if (recorreProcedimientos(dbi, parametros, fileexe, exe)) { + lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r"); + lon += sprintf(ptrTrama->parametros + lon, "nfl=%s\r", fileautoexec); + lon += sprintf(ptrTrama->parametros + lon, "res=1\r"); + } else { + lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r"); + lon += sprintf(ptrTrama->parametros + lon, "res=0\r"); + } + + og_dbi_close(dbi); + fclose(fileexe); + + if (!mandaTrama(&socket_c, ptrTrama)) { + liberaMemoria(exe); + syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + return false; + } + liberaMemoria(exe); + return true; +} +// ________________________________________________________________________________________________________ +// Función: recorreProcedimientos +// +// Descripción: +// Crea un archivo con el código de un procedimiento separando cada comando por un salto de linea +// Parámetros: +// Database db,char* parametros,FILE* fileexe,char* idp +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool recorreProcedimientos(struct og_dbi *dbi, char *parametros, FILE *fileexe, char *idp) +{ + char idprocedimiento[LONPRM]; + int procedimientoid, lsize; + const char *msglog, *param; + dbi_result result; + + result = dbi_conn_queryf(dbi->conn, + "SELECT procedimientoid,parametros FROM procedimientos_acciones" + " WHERE idprocedimiento=%s ORDER BY orden", idp); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + while (dbi_result_next_row(result)) { + procedimientoid = dbi_result_get_uint(result, "procedimientoid"); + if (procedimientoid > 0) { // Procedimiento recursivo + sprintf(idprocedimiento, "%d", procedimientoid); + if (!recorreProcedimientos(dbi, parametros, fileexe, idprocedimiento)) { + return false; + } + } else { + param = dbi_result_get_string(result, "parametros"); + sprintf(parametros, "%s@", param); + lsize = strlen(parametros); + fwrite(parametros, 1, lsize, fileexe); // Escribe el código a ejecutar + } + } + dbi_result_free(result); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: ComandosPendientes +// +// Descripción: +// Esta función busca en la base de datos,comandos pendientes de ejecutar por un ordenador concreto +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool ComandosPendientes(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + char *ido,*iph,pids[LONPRM]; + int ids, idx; + + iph = copiaParametro("iph",ptrTrama); // Toma dirección IP + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!clienteExistente(iph, &idx)) { // Busca índice del cliente + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "client does not exist\n"); + return false; + } + if (buscaComandos(ido, ptrTrama, &ids)) { // Existen comandos pendientes + ptrTrama->tipo = MSG_COMANDO; + sprintf(pids, "\rids=%d\r", ids); + strcat(ptrTrama->parametros, pids); + strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); + } else { + initParametros(ptrTrama,0); + strcpy(ptrTrama->parametros, "nfn=NoComandosPtes\r"); + } + if (!mandaTrama(&socket_c, ptrTrama)) { + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + return false; + } + liberaMemoria(iph); + liberaMemoria(ido); + return true; +} +// ________________________________________________________________________________________________________ +// Función: buscaComandos +// +// Descripción: +// Busca en la base de datos,comandos pendientes de ejecutar por el cliente +// Parámetros: +// - ido: Identificador del ordenador +// - cmd: Parámetros del comando (Salida) +// - ids: Identificador de la sesion(Salida) +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool buscaComandos(char *ido, TRAMA *ptrTrama, int *ids) +{ + const char *param, *msglog; + struct og_dbi *dbi; + dbi_result result; + unsigned int lonprm; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + goto err_dbi_open; + } + result = dbi_conn_queryf(dbi->conn, + "SELECT sesion, parametros"\ + " FROM acciones WHERE idordenador=%s AND estado='%d'"\ + " ORDER BY idaccion", ido, ACCION_INICIADA); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + goto err_query_fail; + } + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + og_dbi_close(dbi); + return false; // No hay comandos pendientes + } + + *ids = dbi_result_get_uint(result, "sesion"); + param = dbi_result_get_string(result, "parametros"); + lonprm = strlen(param); + + if(!initParametros(ptrTrama,lonprm + LONGITUD_PARAMETROS)){ + syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__); + goto err_init_params; + } + sprintf(ptrTrama->parametros, "%s", param); + + dbi_result_free(result); + og_dbi_close(dbi); + + return true; // Hay comandos pendientes, se toma el primero de la cola + +err_init_params: + dbi_result_free(result); +err_query_fail: + og_dbi_close(dbi); +err_dbi_open: + return false; +} +// ________________________________________________________________________________________________________ +// Función: DisponibilidadComandos +// +// Descripción: +// Esta función habilita a un cliente para recibir comandos desde la consola +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +// +static bool DisponibilidadComandos(TRAMA *ptrTrama, struct og_client *cli) +{ + char *iph, *tpc; + int idx; + + iph = copiaParametro("iph",ptrTrama); // Toma ip + if (!clienteExistente(iph, &idx)) { // Busca índice del cliente + liberaMemoria(iph); + syslog(LOG_ERR, "client does not exist\n"); + return false; + } + tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.) + strcpy(tbsockets[idx].estado, tpc); + cli->keepalive_idx = idx; + liberaMemoria(iph); + liberaMemoria(tpc); + return true; +} +// ________________________________________________________________________________________________________ +// Función: respuestaEstandar +// +// Descripción: +// Esta función actualiza la base de datos con el resultado de la ejecución de un comando con seguimiento +// Parámetros: +// - res: resultado de la ejecución del comando +// - der: Descripción del error si hubiese habido +// - iph: Dirección IP +// - ids: identificador de la sesión +// - ido: Identificador del ordenador que notifica +// - db: Objeto base de datos (operativo) +// - tbl: Objeto tabla +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool respuestaEstandar(TRAMA *ptrTrama, char *iph, char *ido, + struct og_dbi *dbi) +{ + char *res, *ids, *der; + char fechafin[LONPRM]; + const char *msglog; + dbi_result result; + struct tm* st; + int idaccion; + + ids = copiaParametro("ids",ptrTrama); + res = copiaParametro("res",ptrTrama); + + if (ids == NULL) { + if (atoi(res) == ACCION_FALLIDA) { + liberaMemoria(res); + return false; + } + liberaMemoria(res); + return true; + } + + if (atoi(ids) == 0) { + liberaMemoria(ids); + if (atoi(res) == ACCION_FALLIDA) { + liberaMemoria(res); + return false; + } + liberaMemoria(res); + return true; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT * FROM acciones WHERE idordenador=%s" + " AND sesion=%s ORDER BY idaccion", ido,ids); + + liberaMemoria(ids); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, "no actions available\n"); + dbi_result_free(result); + return true; + } + + idaccion = dbi_result_get_uint(result, "idaccion"); + dbi_result_free(result); + + st = tomaHora(); + sprintf(fechafin, "%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1, + st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec); + + der = copiaParametro("der",ptrTrama); // Toma descripción del error (si hubiera habido) + + result = dbi_conn_queryf(dbi->conn, + "UPDATE acciones"\ + " SET resultado='%s',estado='%d',fechahorafin='%s',descrinotificacion='%s'"\ + " WHERE idordenador=%s AND idaccion=%d", + res, ACCION_FINALIZADA, fechafin, der, ido, idaccion); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + liberaMemoria(res); + liberaMemoria(der); + og_info((char *)msglog); + return false; + } + dbi_result_free(result); + + liberaMemoria(der); + + if (atoi(res) == ACCION_FALLIDA) { + liberaMemoria(res); + return false; + } + + liberaMemoria(res); + return true; +} + +static bool og_send_cmd(char *ips_array[], int ips_array_len, + const char *state, TRAMA *ptrTrama) +{ + int i, idx; + + for (i = 0; i < ips_array_len; i++) { + if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos + int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1; + + strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente + if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) { + syslog(LOG_ERR, "failed to send response to %s:%s\n", + ips_array[i], strerror(errno)); + } + } + } + return true; +} + +// ________________________________________________________________________________________________________ +// Función: enviaComando +// +// Descripción: +// Envía un comando a los clientes +// Parámetros: +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// - estado: Estado en el se deja al cliente mientras se ejecuta el comando +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool enviaComando(TRAMA* ptrTrama, const char *estado) +{ + char *iph, *Ipes, *ptrIpes[MAXIMOS_CLIENTES]; + int lon; + + iph = copiaParametro("iph",ptrTrama); // Toma dirección/es IP + lon = strlen(iph); // Calcula longitud de la cadena de direccion/es IPE/S + Ipes = (char*) reservaMemoria(lon + 1); + if (Ipes == NULL) { + syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__); + return false; + } + + strcpy(Ipes, iph); // Copia cadena de IPES + liberaMemoria(iph); + + lon = splitCadena(ptrIpes, Ipes, ';'); + FINCADaINTRO(ptrTrama); + + if (!og_send_cmd(ptrIpes, lon, estado, ptrTrama)) + return false; + + liberaMemoria(Ipes); + return true; +} +//______________________________________________________________________________________________________ +// Función: respuestaConsola +// +// Descripción: +// Envia una respuesta a la consola sobre el resultado de la ejecución de un comando +// Parámetros: +// - socket_c: (Salida) Socket utilizado para el envío +// - res: Resultado del envío del comando +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool respuestaConsola(int socket_c, TRAMA *ptrTrama, int res) +{ + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros, "res=%d\r", res); + if (!mandaTrama(&socket_c, ptrTrama)) { + syslog(LOG_ERR, "%s:%d failed to send response: %s\n", + __func__, __LINE__, strerror(errno)); + return false; + } + return true; +} +// ________________________________________________________________________________________________________ +// Función: Levanta +// +// Descripción: +// Enciende ordenadores a través de la red cuyas macs se pasan como parámetro +// Parámetros: +// - iph: Cadena de direcciones ip separadas por ";" +// - mac: Cadena de direcciones mac separadas por ";" +// - mar: Método de arranque (1=Broadcast, 2=Unicast) +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool Levanta(char *ptrIP[], char *ptrMacs[], char *ptrNetmasks[], int lon, char *mar) +{ + unsigned int on = 1; + struct sockaddr_in local; + int i, res; + int s; + + /* Creación de socket para envío de magig packet */ + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) { + syslog(LOG_ERR, "cannot create socket for magic packet\n"); + return false; + } + res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on, + sizeof(on)); + if (res < 0) { + syslog(LOG_ERR, "cannot set broadcast socket\n"); + return false; + } + + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(PUERTO_WAKEUP); + local.sin_addr.s_addr = htonl(INADDR_ANY); + + for (i = 0; i < lon; i++) { + if (!WakeUp(s, ptrIP[i], ptrMacs[i], ptrNetmasks[i], mar)) { + syslog(LOG_ERR, "problem sending magic packet\n"); + close(s); + return false; + } + } + close(s); + return true; +} + +#define OG_WOL_SEQUENCE 6 +#define OG_WOL_MACADDR_LEN 6 +#define OG_WOL_REPEAT 16 + +struct wol_msg { + char secuencia_FF[OG_WOL_SEQUENCE]; + char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN]; +}; + +static bool wake_up_broadcast(int sd, struct sockaddr_in *client, + const struct wol_msg *msg, const struct in_addr *addr) +{ + struct sockaddr_in *broadcast_addr; + struct ifaddrs *ifaddr, *ifa; + int ret1, ret2; + + if (getifaddrs(&ifaddr) < 0) { + syslog(LOG_ERR, "cannot get list of addresses\n"); + return false; + } + + + client->sin_addr.s_addr = htonl(INADDR_BROADCAST); + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_INET || + strcmp(ifa->ifa_name, interface) != 0) + continue; + + broadcast_addr = + (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr; + client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr; + break; + } + freeifaddrs(ifaddr); + + ret1 = sendto(sd, msg, sizeof(*msg), 0, + (struct sockaddr *)client, sizeof(*client)); + client->sin_addr.s_addr = addr->s_addr; + ret2 = sendto(sd, msg, sizeof(*msg), 0, + (struct sockaddr *)client, sizeof(*client)); + if ((ret1 < 0) & (ret2 < 0)) { + syslog(LOG_ERR, "failed to send broadcast wol\n"); + return false; + } + + return true; +} + +static bool wake_up_unicast(int sd, struct sockaddr_in *client, + const struct wol_msg *msg, + const struct in_addr *addr) +{ + int ret; + + client->sin_addr.s_addr = addr->s_addr; + + ret = sendto(sd, msg, sizeof(*msg), 0, + (struct sockaddr *)client, sizeof(*client)); + if (ret < 0) { + syslog(LOG_ERR, "failed to send unicast wol\n"); + return false; + } + + return true; +} + + + +enum wol_delivery_type { + OG_WOL_BROADCAST = 1, + OG_WOL_UNICAST = 2 +}; + +//_____________________________________________________________________________________________________________ +// Función: WakeUp +// +// Descripción: +// Enciende el ordenador cuya MAC se pasa como parámetro +// Parámetros: +// - s : Socket para enviar trama magic packet +// - iph : Cadena con la dirección ip +// - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX +// - mar: Método de arranque (1=Broadcast, 2=Unicast) +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +//_____________________________________________________________________________________________________________ +// +bool WakeUp(int s, char* iph, char *mac, char *netmask, char *mar) +{ + unsigned int macaddr[OG_WOL_MACADDR_LEN]; + char HDaddress_bin[OG_WOL_MACADDR_LEN]; + struct sockaddr_in WakeUpCliente; + struct wol_msg Trama_WakeUp; + struct in_addr addr, netmask_addr, broadcast_addr ={}; + bool ret; + int i; + + if (!inet_aton(iph, &addr)) { + syslog(LOG_ERR, "bad IP address\n"); + return false; + } + + if (!inet_aton(netmask, &netmask_addr)) { + syslog(LOG_ERR, "bad netmask address: %s\n", netmask); + return false; + } + broadcast_addr.s_addr = addr.s_addr | ~netmask_addr.s_addr; + + for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF) + Trama_WakeUp.secuencia_FF[i] = 0xFF; + + sscanf(mac, "%02x%02x%02x%02x%02x%02x", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + + for (i = 0; i < 6; i++) + HDaddress_bin[i] = (uint8_t)macaddr[i]; + + for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC + memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6); + + /* Creación de socket del cliente que recibe la trama magic packet */ + WakeUpCliente.sin_family = AF_INET; + WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP); + + switch (atoi(mar)) { + case OG_WOL_BROADCAST: + ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp, &broadcast_addr ); + break; + case OG_WOL_UNICAST: + ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr); + break; + default: + syslog(LOG_ERR, "unknown wol type\n"); + ret = false; + break; + } + return ret; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_Arrancar +// +// Descripción: +// Respuesta del cliente al comando Arrancar +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_Arrancar(TRAMA* ptrTrama, struct og_client *cli) +{ + struct og_dbi *dbi; + char *iph, *ido; + char *tpc; + int i; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + og_dbi_close(dbi); + return false; + } + + tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.) + if (clienteExistente(iph, &i)) // Actualiza estado + strcpy(tbsockets[i].estado, tpc); + + liberaMemoria(iph); + liberaMemoria(ido); + liberaMemoria(tpc); + og_dbi_close(dbi); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_Apagar +// +// Descripción: +// Respuesta del cliente al comando Apagar +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_Apagar(TRAMA* ptrTrama, struct og_client *cli) +{ + struct og_dbi *dbi; + char *iph, *ido; + int i; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + og_dbi_close(dbi); + return false; // Error al registrar notificacion + } + + if (clienteExistente(iph, &i)) // Actualiza estado + strcpy(tbsockets[i].estado, CLIENTE_APAGADO); + + liberaMemoria(iph); + liberaMemoria(ido); + og_dbi_close(dbi); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_CrearImagen +// +// Descripción: +// Respuesta del cliente al comando CrearImagen +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_CrearImagen(TRAMA* ptrTrama, struct og_client *cli) +{ + char *iph, *dsk, *par, *cpt, *ipr, *ido; + struct og_dbi *dbi; + char *idi; + bool res; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + og_dbi_close(dbi); + return false; // Error al registrar notificacion + } + + // Acciones posteriores + idi = copiaParametro("idi",ptrTrama); + dsk = copiaParametro("dsk",ptrTrama); + par = copiaParametro("par",ptrTrama); + cpt = copiaParametro("cpt",ptrTrama); + ipr = copiaParametro("ipr",ptrTrama); + + res=actualizaCreacionImagen(dbi, idi, dsk, par, cpt, ipr, ido); + + liberaMemoria(idi); + liberaMemoria(par); + liberaMemoria(cpt); + liberaMemoria(ipr); + og_dbi_close(dbi); + + if (!res) + syslog(LOG_ERR, "Problem processing update\n"); + + return res; +} +// ________________________________________________________________________________________________________ +// Función: actualizaCreacionImagen +// +// Descripción: +// Esta función actualiza la base de datos con el resultado de la creación de una imagen +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - idi: Identificador de la imagen +// - dsk: Disco de donde se creó +// - par: Partición de donde se creó +// - cpt: Código de partición +// - ipr: Ip del repositorio +// - ido: Identificador del ordenador modelo +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk, + char *par, char *cpt, char *ipr, char *ido) +{ + const char *msglog; + dbi_result result; + int idr,ifs; + + /* Toma identificador del repositorio correspondiente al ordenador modelo */ + result = dbi_conn_queryf(dbi->conn, + "SELECT repositorios.idrepositorio" + " FROM repositorios" + " LEFT JOIN ordenadores USING (idrepositorio)" + " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, + "repository does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + return false; + } + idr = dbi_result_get_uint(result, "idrepositorio"); + dbi_result_free(result); + + /* Toma identificador del perfilsoftware */ + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilsoft" + " FROM ordenadores_particiones" + " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, + "software profile does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + return false; + } + ifs = dbi_result_get_uint(result, "idperfilsoft"); + dbi_result_free(result); + + /* Actualizar los datos de la imagen */ + result = dbi_conn_queryf(dbi->conn, + "UPDATE imagenes" + " SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s," + " idperfilsoft=%d, idrepositorio=%d," + " fechacreacion=NOW(), revision=revision+1" + " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + /* Actualizar los datos en el cliente */ + result = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores_particiones" + " SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s)," + " fechadespliegue=NOW()" + " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", + idi, idi, ido, dsk, par); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_CrearImagenBasica +// +// Descripción: +// Respuesta del cliente al comando CrearImagenBasica +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli) +{ + // La misma respuesta que la creación de imagen monolítica + return RESPUESTA_CrearImagen(ptrTrama, cli); +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_CrearSoftIncremental +// +// Descripción: +// Respuesta del cliente al comando crearImagenDiferencial +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli) +{ + char *iph,*par,*ido,*idf; + int ifs; + const char *msglog; + struct og_dbi *dbi; + dbi_result result; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + og_dbi_close(dbi); + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + return false; + } + + par = copiaParametro("par",ptrTrama); + + /* Toma identificador del perfilsoftware creado por el inventario de software */ + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilsoft FROM ordenadores_particiones WHERE idordenador=%s AND numpar=%s", + ido, par); + liberaMemoria(iph); + liberaMemoria(ido); + liberaMemoria(par); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + og_dbi_close(dbi); + return false; + } + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, + "software profile does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + og_dbi_close(dbi); + return false; + } + ifs = dbi_result_get_uint(result, "idperfilsoft"); + dbi_result_free(result); + + /* Actualizar los datos de la imagen */ + idf = copiaParametro("idf", ptrTrama); + result = dbi_conn_queryf(dbi->conn, + "UPDATE imagenes SET idperfilsoft=%d WHERE idimagen=%s", + ifs, idf); + liberaMemoria(idf); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + og_dbi_close(dbi); + return false; + } + dbi_result_free(result); + + og_dbi_close(dbi); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_RestaurarImagen +// +// Descripción: +// Respuesta del cliente al comando RestaurarImagen +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +// +static bool RESPUESTA_RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli) +{ + bool res; + char *iph, *ido, *idi, *dsk, *par, *ifs, *cfg; + struct og_dbi *dbi; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + og_dbi_close(dbi); + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + return false; + } + + // Acciones posteriores + idi = copiaParametro("idi",ptrTrama); // Toma identificador de la imagen + dsk = copiaParametro("dsk",ptrTrama); // Número de disco + par = copiaParametro("par",ptrTrama); // Número de partición + ifs = copiaParametro("ifs",ptrTrama); // Identificador del perfil software contenido + cfg = copiaParametro("cfg",ptrTrama); // Configuración de discos + if(cfg){ + actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador + liberaMemoria(cfg); + } + res=actualizaRestauracionImagen(dbi, idi, dsk, par, ido, ifs); + + liberaMemoria(iph); + liberaMemoria(ido); + liberaMemoria(idi); + liberaMemoria(par); + liberaMemoria(ifs); + og_dbi_close(dbi); + + if(!res) + syslog(LOG_ERR, "Problem after restoring image\n"); + + return res; +} +// ________________________________________________________________________________________________________ +// +// Función: RESPUESTA_RestaurarImagenBasica +// +// Descripción: +// Respuesta del cliente al comando RestaurarImagen +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +// +static bool RESPUESTA_RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli) +{ + return RESPUESTA_RestaurarImagen(ptrTrama, cli); +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_RestaurarSoftIncremental +// +// Descripción: +// Respuesta del cliente al comando RestaurarSoftIncremental +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli) +{ + return RESPUESTA_RestaurarImagen(ptrTrama, cli); +} +// ________________________________________________________________________________________________________ +// Función: actualizaRestauracionImagen +// +// Descripción: +// Esta función actualiza la base de datos con el resultado de la restauración de una imagen +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - idi: Identificador de la imagen +// - dsk: Disco de donde se restauró +// - par: Partición de donde se restauró +// - ido: Identificador del cliente donde se restauró +// - ifs: Identificador del perfil software contenido en la imagen +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi, + char *dsk, char *par, char *ido, char *ifs) +{ + const char *msglog; + dbi_result result; + + /* Actualizar los datos de la imagen */ + result = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores_particiones" + " SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW()," + " revision=(SELECT revision FROM imagenes WHERE idimagen=%s)," + " idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)" + " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_EjecutarScript +// +// Descripción: +// Respuesta del cliente al comando EjecutarScript +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_EjecutarScript(TRAMA* ptrTrama, struct og_client *cli) +{ + char *iph, *ido,*cfg; + struct og_dbi *dbi; + bool res = true; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + og_dbi_close(dbi); + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + return false; + } + + cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones + if(cfg){ + res = actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador + liberaMemoria(cfg); + } + + liberaMemoria(iph); + liberaMemoria(ido); + og_dbi_close(dbi); + + if (!res) + syslog(LOG_ERR, "Problem updating client configuration\n"); + + return res; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_InventarioHardware +// +// Descripción: +// Respuesta del cliente al comando InventarioHardware +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_InventarioHardware(TRAMA* ptrTrama, struct og_client *cli) +{ + bool res; + char *iph, *ido, *idc, *npc, *hrd, *buffer; + struct og_dbi *dbi; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip del cliente + ido = copiaParametro("ido",ptrTrama); // Toma identificador del cliente + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + og_dbi_close(dbi); + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + return false; + } + // Lee archivo de inventario enviado anteriormente + hrd = copiaParametro("hrd",ptrTrama); + buffer = rTrim(leeArchivo(hrd)); + + npc = copiaParametro("npc",ptrTrama); + idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro + + if (buffer) + res=actualizaHardware(dbi, buffer, ido, npc, idc); + else + res = false; + + liberaMemoria(iph); + liberaMemoria(ido); + liberaMemoria(npc); + liberaMemoria(idc); + liberaMemoria(buffer); + og_dbi_close(dbi); + + if (!res) + syslog(LOG_ERR, "Problem updating client configuration\n"); + + return res; +} +// ________________________________________________________________________________________________________ +// Función: actualizaHardware +// +// Descripción: +// Actualiza la base de datos con la configuracion hardware del cliente +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - hrd: cadena con el inventario hardware +// - ido: Identificador del ordenador +// - npc: Nombre del ordenador +// - idc: Identificador del centro o Unidad organizativa +// ________________________________________________________________________________________________________ +// +bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc, + char *idc) +{ + const char *msglog; + int idtipohardware, idperfilhard; + int lon, i, j, aux; + bool retval; + char *whard; + int tbidhardware[MAXHARDWARE]; + char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares; + dbi_result result; + + /* Toma Centro (Unidad Organizativa) */ + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s", + ido); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + syslog(LOG_ERR, "client does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + return false; + } + idperfilhard = dbi_result_get_uint(result, "idperfilhard"); + dbi_result_free(result); + + whard=escaparCadena(hrd); // Codificar comillas simples + if(!whard) + return false; + /* Recorre componentes hardware*/ + lon = splitCadena(tbHardware, whard, '\n'); + if (lon > MAXHARDWARE) + lon = MAXHARDWARE; // Limita el número de componentes hardware + /* + for (i=0;iconn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { // Tipo de Hardware NO existente + dbi_result_free(result); + return false; + } else { // Tipo de Hardware Existe + idtipohardware = dbi_result_get_uint(result, "idtipohardware"); + dbi_result_free(result); + + result = dbi_conn_queryf(dbi->conn, + "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'", + idtipohardware, dualHardware[1]); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + + if (!dbi_result_next_row(result)) { // Hardware NO existente + dbi_result_free(result); + result = dbi_conn_queryf(dbi->conn, + "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) " + " VALUES(%d,'%s',%s,0)", idtipohardware, + dualHardware[1], idc); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + + // Recupera el identificador del hardware + tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL); + } else { + tbidhardware[i] = dbi_result_get_uint(result, "idhardware"); + } + dbi_result_free(result); + } + } + // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones + + for (i = 0; i < lon - 1; i++) { + for (j = i + 1; j < lon; j++) { + if (tbidhardware[i] > tbidhardware[j]) { + aux = tbidhardware[i]; + tbidhardware[i] = tbidhardware[j]; + tbidhardware[j] = aux; + } + } + } + /* Crea cadena de identificadores de componentes hardware separados por coma */ + sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud + aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles + idhardwares = reservaMemoria(sizeof(aux) * lon + lon); + if (idhardwares == NULL) { + syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__); + return false; + } + aux = sprintf(idhardwares, "%d", tbidhardware[0]); + for (i = 1; i < lon; i++) + aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]); + + if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares, + npc, tbidhardware, lon)) { + syslog(LOG_ERR, "Problem updating client hardware\n"); + retval=false; + } + else { + retval=true; + } + liberaMemoria(whard); + liberaMemoria(idhardwares); + return (retval); +} +// ________________________________________________________________________________________________________ +// Función: cuestionPerfilHardware +// +// Descripción: +// Comprueba existencia de perfil hardware y actualización de éste para el ordenador +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - idc: Identificador de la Unidad organizativa donde se encuentra el cliente +// - ido: Identificador del ordenador +// - tbidhardware: Identificador del tipo de hardware +// - con: Número de componentes detectados para configurar un el perfil hardware +// - npc: Nombre del cliente +// ________________________________________________________________________________________________________ +bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido, + int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware, + int lon) +{ + const char *msglog; + dbi_result result; + int i; + int nwidperfilhard; + + // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilhard FROM" + " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard," + " group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )" + " ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares" + " FROM perfileshard_hardwares" + " GROUP BY perfileshard_hardwares.idperfilhard) AS temp" + " WHERE idhardwares LIKE '%s'", idhardwares); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { + // No existe un perfil hardware con esos componentes de componentes hardware, lo crea + dbi_result_free(result); + result = dbi_conn_queryf(dbi->conn, + "INSERT perfileshard (descripcion,idcentro,grupoid)" + " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + // Recupera el identificador del nuevo perfil hardware + nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL); + + // Crea la relación entre perfiles y componenetes hardware + for (i = 0; i < lon; i++) { + result = dbi_conn_queryf(dbi->conn, + "INSERT perfileshard_hardwares (idperfilhard,idhardware)" + " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + } + } else { // Existe un perfil con todos esos componentes + nwidperfilhard = dbi_result_get_uint(result, "idperfilhard"); + dbi_result_free(result); + } + if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles + // Actualiza el identificador del perfil hardware del ordenador + result = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores SET idperfilhard=%d" + " WHERE idordenador=%s", nwidperfilhard, ido); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + } + /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN " + " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN" + " (SELECT DISTINCT idperfilhard from ordenadores))"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + /* Eliminar Perfiles hardware que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfileshard WHERE idperfilhard NOT IN" + " (SELECT DISTINCT idperfilhard FROM ordenadores)"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN" + " (SELECT idperfilhard FROM perfileshard)"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + dbi_result_free(result); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: RESPUESTA_InventarioSoftware +// +// Descripción: +// Respuesta del cliente al comando InventarioSoftware +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool RESPUESTA_InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli) +{ + bool res; + char *iph, *ido, *npc, *idc, *par, *sft, *buffer; + struct og_dbi *dbi; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + iph = copiaParametro("iph",ptrTrama); // Toma dirección ip + ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador + + if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) { + og_dbi_close(dbi); + liberaMemoria(iph); + liberaMemoria(ido); + syslog(LOG_ERR, "failed to register notification\n"); + return false; + } + + npc = copiaParametro("npc",ptrTrama); + idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro + par = copiaParametro("par",ptrTrama); + sft = copiaParametro("sft",ptrTrama); + + buffer = rTrim(leeArchivo(sft)); + if (buffer) + res=actualizaSoftware(dbi, buffer, par, ido, npc, idc); + else + res = false; + + liberaMemoria(iph); + liberaMemoria(ido); + liberaMemoria(npc); + liberaMemoria(idc); + liberaMemoria(par); + liberaMemoria(sft); + og_dbi_close(dbi); + + if (!res) + syslog(LOG_ERR, "cannot update software\n"); + + return res; +} +// ________________________________________________________________________________________________________ +// Función: actualizaSoftware +// +// Descripción: +// Actualiza la base de datos con la configuración software del cliente +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - sft: cadena con el inventario software +// - par: Número de la partición +// - ido: Identificador del ordenador del cliente en la tabla +// - npc: Nombre del ordenador +// - idc: Identificador del centro o Unidad organizativa +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// +// Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla +// ________________________________________________________________________________________________________ +bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido, + char *npc, char *idc) +{ + int i, j, lon, aux, idperfilsoft, idnombreso; + bool retval; + char *wsft; + int tbidsoftware[MAXSOFTWARE]; + char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares; + const char *msglog; + dbi_result result; + + /* Toma Centro (Unidad Organizativa) y perfil software */ + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilsoft,numpar" + " FROM ordenadores_particiones" + " WHERE idordenador=%s", ido); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software + while (dbi_result_next_row(result)) { + aux = dbi_result_get_uint(result, "numpar"); + if (aux == atoi(par)) { // Se encuentra la partición + idperfilsoft = dbi_result_get_uint(result, "idperfilsoft"); + break; + } + } + dbi_result_free(result); + wsft=escaparCadena(sft); // Codificar comillas simples + if(!wsft) + return false; + + /* Recorre componentes software*/ + lon = splitCadena(tbSoftware, wsft, '\n'); + + if (lon == 0) + return true; // No hay lineas que procesar + if (lon > MAXSOFTWARE) + lon = MAXSOFTWARE; // Limita el número de componentes software + + idnombreso = 0; + for (i = 0; i < lon; i++) { + // Primera línea es el sistema operativo: se obtiene identificador + if (i == 0) { + idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso"); + continue; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT idsoftware FROM softwares WHERE descripcion ='%s'", + rTrim(tbSoftware[i])); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + result = dbi_conn_queryf(dbi->conn, + "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)" + " VALUES(2,'%s',%s,0)", tbSoftware[i], idc); + if (!result) { // Error al insertar + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + + // Recupera el identificador del software + tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL); + } else { + tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware"); + } + dbi_result_free(result); + } + + // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones + + for (i = 0; i < lon - 1; i++) { + for (j = i + 1; j < lon; j++) { + if (tbidsoftware[i] > tbidsoftware[j]) { + aux = tbidsoftware[i]; + tbidsoftware[i] = tbidsoftware[j]; + tbidsoftware[j] = aux; + } + } + } + /* Crea cadena de identificadores de componentes software separados por coma */ + sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud + aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles + idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon); + if (idsoftwares == NULL) { + syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__); + return false; + } + aux = sprintf(idsoftwares, "%d", tbidsoftware[0]); + for (i = 1; i < lon; i++) + aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]); + + // Comprueba existencia de perfil software y actualización de éste para el ordenador + if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares, + npc, par, tbidsoftware, lon)) { + syslog(LOG_ERR, "cannot update software\n"); + og_info((char *)msglog); + retval=false; + } + else { + retval=true; + } + liberaMemoria(wsft); + liberaMemoria(idsoftwares); + return (retval); +} +// ________________________________________________________________________________________________________ +// Función: CuestionPerfilSoftware +// +// Parámetros: +// - db: Objeto base de datos (ya operativo) +// - tbl: Objeto tabla +// - idcentro: Identificador del centro en la tabla +// - ido: Identificador del ordenador del cliente en la tabla +// - idnombreso: Identificador del sistema operativo +// - idsoftwares: Cadena con los identificadores de componentes software separados por comas +// - npc: Nombre del ordenador del cliente +// - particion: Número de la partición +// - tbidsoftware: Array con los identificadores de componentes software +// - lon: Número de componentes +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// +// Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla +//_________________________________________________________________________________________________________ +bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido, + int idperfilsoftware, int idnombreso, + char *idsoftwares, char *npc, char *par, + int *tbidsoftware, int lon) +{ + int i, nwidperfilsoft; + const char *msglog; + dbi_result result; + + // Busca perfil soft del ordenador que contenga todos los componentes software encontrados + result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilsoft FROM" + " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft," + " group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )" + " ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares" + " FROM perfilessoft_softwares" + " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp" + " WHERE idsoftwares LIKE '%s'", idsoftwares); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return false; + } + if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea + dbi_result_free(result); + result = dbi_conn_queryf(dbi->conn, + "INSERT perfilessoft (descripcion, idcentro, grupoid, idnombreso)" + " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + + dbi_result_free(result); + // Recupera el identificador del nuevo perfil software + nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL); + + // Crea la relación entre perfiles y componenetes software + for (i = 0; i < lon; i++) { + result = dbi_conn_queryf(dbi->conn, + "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)" + " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + dbi_result_free(result); + } + } else { // Existe un perfil con todos esos componentes + nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft"); + dbi_result_free(result); + } + + if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles + // Actualiza el identificador del perfil software del ordenador + result = dbi_conn_queryf(dbi->conn, + "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0" + " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par); + if (!result) { // Error al insertar + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + dbi_result_free(result); + } + + /* DEPURACIÓN DE PERFILES SOFTWARE */ + + /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\ + " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\ + " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\ + " (SELECT DISTINCT idperfilsoft from imagenes))"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + dbi_result_free(result), + /* Eliminar Perfiles software que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN" + " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\ + " AND idperfilsoft NOT IN"\ + " (SELECT DISTINCT idperfilsoft from imagenes)"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + dbi_result_free(result), + + /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */ + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN" + " (SELECT idperfilsoft from perfilessoft)"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + og_info((char *)msglog); + return false; + } + dbi_result_free(result); + + return true; +} +// ________________________________________________________________________________________________________ +// Función: enviaArchivo +// +// Descripción: +// Envia un archivo por la red, por bloques +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool enviaArchivo(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + char *nfl; + + // Toma parámetros + nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo + if (!sendArchivo(&socket_c, nfl)) { + liberaMemoria(nfl); + syslog(LOG_ERR, "Problem sending file\n"); + return false; + } + liberaMemoria(nfl); + return true; +} +// ________________________________________________________________________________________________________ +// Función: enviaArchivo +// +// Descripción: +// Envia un archivo por la red, por bloques +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool recibeArchivo(TRAMA *ptrTrama, struct og_client *cli) +{ + int socket_c = og_client_socket(cli); + char *nfl; + + // Toma parámetros + nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo + ptrTrama->tipo = MSG_NOTIFICACION; + enviaFlag(&socket_c, ptrTrama); + if (!recArchivo(&socket_c, nfl)) { + liberaMemoria(nfl); + syslog(LOG_ERR, "Problem receiving file\n"); + return false; + } + liberaMemoria(nfl); + return true; +} +// ________________________________________________________________________________________________________ +// Función: envioProgramacion +// +// Descripción: +// Envia un comando de actualización a todos los ordenadores que han sido programados con +// alguna acción para que entren en el bucle de comandos pendientes y las ejecuten +// Parámetros: +// - socket_c: Socket del cliente que envió el mensaje +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static bool envioProgramacion(TRAMA *ptrTrama, struct og_client *cli) +{ + char *ptrIP[MAXIMOS_CLIENTES],*ptrMacs[MAXIMOS_CLIENTES],*ptrNetmasks[MAXIMOS_CLIENTES]; + char *idp, *iph, *mac, *netmask; + int idx,idcomando,lon; + const char *msglog; + struct og_dbi *dbi; + dbi_result result; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return false; + } + + idp = copiaParametro("idp",ptrTrama); // Toma identificador de la programación de la tabla acciones + + result = dbi_conn_queryf(dbi->conn, + "SELECT ordenadores.ip,ordenadores.mac,aulas.netmask, acciones.idcomando FROM acciones "\ + " INNER JOIN ordenadores ON ordenadores.ip=acciones.ip"\ + " INNER JOIN aulas ON ordenadores.idaula=aulas.idaula "\ + " WHERE acciones.idprogramacion=%s",idp); + + liberaMemoria(idp); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + og_dbi_close(dbi); + return false; + } + + /* Prepara la trama de actualizacion */ + + initParametros(ptrTrama,0); + ptrTrama->tipo=MSG_COMANDO; + sprintf(ptrTrama->parametros, "nfn=Actualizar\r"); + + while (dbi_result_next_row(result)) { + iph = (char *)dbi_result_get_string(result, "ip"); + idcomando = dbi_result_get_uint(result, "idcomando"); + + if (idcomando == 1){ // Arrancar + mac = (char *)dbi_result_get_string(result, "mac"); + netmask = (char *)dbi_result_get_string(result, "netmask"); + lon = splitCadena(ptrIP, iph, ';'); + lon = splitCadena(ptrMacs, mac, ';'); + lon = splitCadena(ptrNetmasks, netmask, ';'); + + // Se manda por broadcast y por unicast + if (!Levanta(ptrIP, ptrMacs, ptrNetmasks, lon, (char*)"1")) { + dbi_result_free(result); + og_dbi_close(dbi); + return false; + } + + if (!Levanta(ptrIP, ptrMacs, ptrNetmasks, lon, (char*)"2")) { + dbi_result_free(result); + og_dbi_close(dbi); + return false; + } + + } + if (clienteDisponible(iph, &idx)) { // Si el cliente puede recibir comandos + int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1; + + strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); // Actualiza el estado del cliente + if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) { + syslog(LOG_ERR, "failed to send response: %s\n", + strerror(errno)); + } + //close(tbsockets[idx].sock); // Cierra el socket del cliente hasta nueva disponibilidad + } + } + dbi_result_free(result); + og_dbi_close(dbi); + + return true; // No existen registros +} + +// This object stores function handler for messages +static struct { + const char *nf; // Nombre de la función + bool (*fcn)(TRAMA *, struct og_client *cli); +} tbfuncionesServer[] = { + { "InclusionCliente", InclusionCliente, }, + { "InclusionClienteWinLnx", InclusionClienteWinLnx, }, + { "AutoexecCliente", AutoexecCliente, }, + { "ComandosPendientes", ComandosPendientes, }, + { "DisponibilidadComandos", DisponibilidadComandos, }, + { "RESPUESTA_Arrancar", RESPUESTA_Arrancar, }, + { "RESPUESTA_Apagar", RESPUESTA_Apagar, }, + { "RESPUESTA_Reiniciar", RESPUESTA_Apagar, }, + { "RESPUESTA_IniciarSesion", RESPUESTA_Apagar, }, + { "RESPUESTA_CrearImagen", RESPUESTA_CrearImagen, }, + { "RESPUESTA_CrearImagenBasica", RESPUESTA_CrearImagenBasica, }, + { "RESPUESTA_CrearSoftIncremental", RESPUESTA_CrearSoftIncremental, }, + { "RESPUESTA_RestaurarImagen", RESPUESTA_RestaurarImagen }, + { "RESPUESTA_RestaurarImagenBasica", RESPUESTA_RestaurarImagenBasica, }, + { "RESPUESTA_RestaurarSoftIncremental", RESPUESTA_RestaurarSoftIncremental, }, + { "RESPUESTA_Configurar", RESPUESTA_EjecutarScript, }, + { "RESPUESTA_EjecutarScript", RESPUESTA_EjecutarScript, }, + { "RESPUESTA_InventarioHardware", RESPUESTA_InventarioHardware, }, + { "RESPUESTA_InventarioSoftware", RESPUESTA_InventarioSoftware, }, + { "enviaArchivo", enviaArchivo, }, + { "recibeArchivo", recibeArchivo, }, + { "envioProgramacion", envioProgramacion, }, + { NULL, NULL, }, +}; + +// ________________________________________________________________________________________________________ +// Función: gestionaTrama +// +// Descripción: +// Procesa las tramas recibidas . +// Parametros: +// - s : Socket usado para comunicaciones +// Devuelve: +// true: Si el proceso es correcto +// false: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +static void gestionaTrama(TRAMA *ptrTrama, struct og_client *cli) +{ + int i, res; + char *nfn; + + if (ptrTrama){ + INTROaFINCAD(ptrTrama); + nfn = copiaParametro("nfn",ptrTrama); // Toma nombre de la función + + for (i = 0; tbfuncionesServer[i].fcn; i++) { + if (!strncmp(tbfuncionesServer[i].nf, nfn, + strlen(tbfuncionesServer[i].nf))) { + res = tbfuncionesServer[i].fcn(ptrTrama, cli); + if (!res) { + syslog(LOG_ERR, "Failed handling of %s for client %s:%hu\n", + tbfuncionesServer[i].nf, + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + } else { + syslog(LOG_DEBUG, "Successful handling of %s for client %s:%hu\n", + tbfuncionesServer[i].nf, + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + } + break; + } + } + if (!tbfuncionesServer[i].fcn) + syslog(LOG_ERR, "unknown request %s from client %s:%hu\n", + nfn, inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + + liberaMemoria(nfn); + } +} + +static void og_client_release(struct ev_loop *loop, struct og_client *cli) +{ + if (cli->keepalive_idx >= 0) { + syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port), cli->keepalive_idx); + tbsockets[cli->keepalive_idx].cli = NULL; + } + + ev_io_stop(loop, &cli->io); + close(cli->io.fd); + free(cli); +} + +static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli) +{ + struct og_client *old_cli; + + old_cli = tbsockets[cli->keepalive_idx].cli; + if (old_cli && old_cli != cli) { + syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n", + inet_ntoa(old_cli->addr.sin_addr), + ntohs(old_cli->addr.sin_port)); + + og_client_release(loop, old_cli); + } + tbsockets[cli->keepalive_idx].cli = cli; +} + +static void og_client_reset_state(struct og_client *cli) +{ + cli->state = OG_CLIENT_RECEIVING_HEADER; + cli->buf_len = 0; +} + +static int og_client_state_recv_hdr(struct og_client *cli) +{ + char hdrlen[LONHEXPRM]; + + /* Still too short to validate protocol fingerprint and message + * length. + */ + if (cli->buf_len < 15 + LONHEXPRM) + return 0; + + if (strncmp(cli->buf, "@JMMLCAMDJ_MCDJ", 15)) { + syslog(LOG_ERR, "bad fingerprint from client %s:%hu, closing\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + return -1; + } + + memcpy(hdrlen, &cli->buf[LONGITUD_CABECERATRAMA], LONHEXPRM); + cli->msg_len = strtol(hdrlen, NULL, 16); + + /* Header announces more that we can fit into buffer. */ + if (cli->msg_len >= sizeof(cli->buf)) { + syslog(LOG_ERR, "too large message %u bytes from %s:%hu\n", + cli->msg_len, inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + return -1; + } + + return 1; +} + +static TRAMA *og_msg_alloc(char *data, unsigned int len) +{ + TRAMA *ptrTrama; + + ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA)); + if (!ptrTrama) { + syslog(LOG_ERR, "OOM\n"); + return NULL; + } + + initParametros(ptrTrama, len); + memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA); + memcpy(ptrTrama->parametros, data, len); + ptrTrama->lonprm = len; + + return ptrTrama; +} + +static void og_msg_free(TRAMA *ptrTrama) +{ + liberaMemoria(ptrTrama->parametros); + liberaMemoria(ptrTrama); +} + +static int og_client_state_process_payload(struct og_client *cli) +{ + TRAMA *ptrTrama; + char *data; + int len; + + len = cli->msg_len - (LONGITUD_CABECERATRAMA + LONHEXPRM); + data = &cli->buf[LONGITUD_CABECERATRAMA + LONHEXPRM]; + + ptrTrama = og_msg_alloc(data, len); + if (!ptrTrama) + return -1; + + gestionaTrama(ptrTrama, cli); + + og_msg_free(ptrTrama); + + return 1; +} + +#define OG_CLIENTS_MAX 4096 +#define OG_PARTITION_MAX 4 + +struct og_partition { + const char *number; + const char *code; + const char *size; + const char *filesystem; + const char *format; +}; + +struct og_sync_params { + const char *sync; + const char *diff; + const char *remove; + const char *compress; + const char *cleanup; + const char *cache; + const char *cleanup_cache; + const char *remove_dst; + const char *diff_id; + const char *diff_name; + const char *path; + const char *method; +}; + +struct og_msg_params { + const char *ips_array[OG_CLIENTS_MAX]; + const char *mac_array[OG_CLIENTS_MAX]; + const char *netmask_array[OG_CLIENTS_MAX]; + unsigned int ips_array_len; + const char *wol_type; + char run_cmd[4096]; + const char *disk; + const char *partition; + const char *repository; + const char *name; + const char *id; + const char *code; + const char *type; + const char *profile; + const char *cache; + const char *cache_size; + bool echo; + struct og_partition partition_setup[OG_PARTITION_MAX]; + struct og_sync_params sync_setup; + uint64_t flags; +}; + +#define OG_REST_PARAM_ADDR (1UL << 0) +#define OG_REST_PARAM_MAC (1UL << 1) +#define OG_REST_PARAM_WOL_TYPE (1UL << 2) +#define OG_REST_PARAM_RUN_CMD (1UL << 3) +#define OG_REST_PARAM_DISK (1UL << 4) +#define OG_REST_PARAM_PARTITION (1UL << 5) +#define OG_REST_PARAM_REPO (1UL << 6) +#define OG_REST_PARAM_NAME (1UL << 7) +#define OG_REST_PARAM_ID (1UL << 8) +#define OG_REST_PARAM_CODE (1UL << 9) +#define OG_REST_PARAM_TYPE (1UL << 10) +#define OG_REST_PARAM_PROFILE (1UL << 11) +#define OG_REST_PARAM_CACHE (1UL << 12) +#define OG_REST_PARAM_CACHE_SIZE (1UL << 13) +#define OG_REST_PARAM_PART_0 (1UL << 14) +#define OG_REST_PARAM_PART_1 (1UL << 15) +#define OG_REST_PARAM_PART_2 (1UL << 16) +#define OG_REST_PARAM_PART_3 (1UL << 17) +#define OG_REST_PARAM_SYNC_SYNC (1UL << 18) +#define OG_REST_PARAM_SYNC_DIFF (1UL << 19) +#define OG_REST_PARAM_SYNC_REMOVE (1UL << 20) +#define OG_REST_PARAM_SYNC_COMPRESS (1UL << 21) +#define OG_REST_PARAM_SYNC_CLEANUP (1UL << 22) +#define OG_REST_PARAM_SYNC_CACHE (1UL << 23) +#define OG_REST_PARAM_SYNC_CLEANUP_CACHE (1UL << 24) +#define OG_REST_PARAM_SYNC_REMOVE_DST (1UL << 25) +#define OG_REST_PARAM_SYNC_DIFF_ID (1UL << 26) +#define OG_REST_PARAM_SYNC_DIFF_NAME (1UL << 27) +#define OG_REST_PARAM_SYNC_PATH (1UL << 28) +#define OG_REST_PARAM_SYNC_METHOD (1UL << 29) +#define OG_REST_PARAM_ECHO (1UL << 30) + +static bool og_msg_params_validate(const struct og_msg_params *params, + const uint64_t flags) +{ + return (params->flags & flags) == flags; +} + +static int og_json_parse_clients(json_t *element, struct og_msg_params *params) +{ + unsigned int i; + json_t *k; + + if (json_typeof(element) != JSON_ARRAY) + return -1; + + for (i = 0; i < json_array_size(element); i++) { + k = json_array_get(element, i); + if (json_typeof(k) != JSON_STRING) + return -1; + + params->ips_array[params->ips_array_len++] = + json_string_value(k); + + params->flags |= OG_REST_PARAM_ADDR; + } + + return 0; +} + +static int og_json_parse_string(json_t *element, const char **str) +{ + if (json_typeof(element) != JSON_STRING) + return -1; + + *str = json_string_value(element); + return 0; +} + +static int og_json_parse_bool(json_t *element, bool *value) +{ + if (json_typeof(element) == JSON_TRUE) + *value = true; + else if (json_typeof(element) == JSON_FALSE) + *value = false; + else + return -1; + + return 0; +} + +static int og_json_parse_sync_params(json_t *element, + struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "sync")) { + err = og_json_parse_string(value, ¶ms->sync_setup.sync); + params->flags |= OG_REST_PARAM_SYNC_SYNC; + } else if (!strcmp(key, "diff")) { + err = og_json_parse_string(value, ¶ms->sync_setup.diff); + params->flags |= OG_REST_PARAM_SYNC_DIFF; + } else if (!strcmp(key, "remove")) { + err = og_json_parse_string(value, ¶ms->sync_setup.remove); + params->flags |= OG_REST_PARAM_SYNC_REMOVE; + } else if (!strcmp(key, "compress")) { + err = og_json_parse_string(value, ¶ms->sync_setup.compress); + params->flags |= OG_REST_PARAM_SYNC_COMPRESS; + } else if (!strcmp(key, "cleanup")) { + err = og_json_parse_string(value, ¶ms->sync_setup.cleanup); + params->flags |= OG_REST_PARAM_SYNC_CLEANUP; + } else if (!strcmp(key, "cache")) { + err = og_json_parse_string(value, ¶ms->sync_setup.cache); + params->flags |= OG_REST_PARAM_SYNC_CACHE; + } else if (!strcmp(key, "cleanup_cache")) { + err = og_json_parse_string(value, ¶ms->sync_setup.cleanup_cache); + params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE; + } else if (!strcmp(key, "remove_dst")) { + err = og_json_parse_string(value, ¶ms->sync_setup.remove_dst); + params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST; + } else if (!strcmp(key, "diff_id")) { + err = og_json_parse_string(value, ¶ms->sync_setup.diff_id); + params->flags |= OG_REST_PARAM_SYNC_DIFF_ID; + } else if (!strcmp(key, "diff_name")) { + err = og_json_parse_string(value, ¶ms->sync_setup.diff_name); + params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME; + } else if (!strcmp(key, "path")) { + err = og_json_parse_string(value, ¶ms->sync_setup.path); + params->flags |= OG_REST_PARAM_SYNC_PATH; + } else if (!strcmp(key, "method")) { + err = og_json_parse_string(value, ¶ms->sync_setup.method); + params->flags |= OG_REST_PARAM_SYNC_METHOD; + } + + if (err != 0) + return err; + } + return err; +} + +#define OG_PARAM_PART_NUMBER (1UL << 0) +#define OG_PARAM_PART_CODE (1UL << 1) +#define OG_PARAM_PART_FILESYSTEM (1UL << 2) +#define OG_PARAM_PART_SIZE (1UL << 3) +#define OG_PARAM_PART_FORMAT (1UL << 4) + +static int og_json_parse_partition(json_t *element, + struct og_msg_params *params, + unsigned int i) +{ + struct og_partition *part = ¶ms->partition_setup[i]; + uint64_t flags = 0UL; + const char *key; + json_t *value; + int err = 0; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, &part->number); + flags |= OG_PARAM_PART_NUMBER; + } else if (!strcmp(key, "code")) { + err = og_json_parse_string(value, &part->code); + flags |= OG_PARAM_PART_CODE; + } else if (!strcmp(key, "filesystem")) { + err = og_json_parse_string(value, &part->filesystem); + flags |= OG_PARAM_PART_FILESYSTEM; + } else if (!strcmp(key, "size")) { + err = og_json_parse_string(value, &part->size); + flags |= OG_PARAM_PART_SIZE; + } else if (!strcmp(key, "format")) { + err = og_json_parse_string(value, &part->format); + flags |= OG_PARAM_PART_FORMAT; + } + + if (err < 0) + return err; + } + + if (flags != (OG_PARAM_PART_NUMBER | + OG_PARAM_PART_CODE | + OG_PARAM_PART_FILESYSTEM | + OG_PARAM_PART_SIZE | + OG_PARAM_PART_FORMAT)) + return -1; + + params->flags |= (OG_REST_PARAM_PART_0 << i); + + return err; +} + +static int og_json_parse_partition_setup(json_t *element, + struct og_msg_params *params) +{ + unsigned int i; + json_t *k; + + if (json_typeof(element) != JSON_ARRAY) + return -1; + + for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) { + k = json_array_get(element, i); + + if (json_typeof(k) != JSON_OBJECT) + return -1; + + if (og_json_parse_partition(k, params, i) != 0) + return -1; + } + return 0; +} + +static int og_cmd_legacy_send(struct og_msg_params *params, const char *cmd, + const char *state) +{ + char buf[4096] = {}; + int len, err = 0; + TRAMA *msg; + + len = snprintf(buf, sizeof(buf), "nfn=%s\r", cmd); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + if (!og_send_cmd((char **)params->ips_array, params->ips_array_len, + state, msg)) + err = -1; + + og_msg_free(msg); + + return err; +} + +static int og_cmd_post_clients(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "Sondeo", CLIENTE_APAGADO); +} + +struct og_buffer { + char *data; + int len; +}; + +static int og_json_dump_clients(const char *buffer, size_t size, void *data) +{ + struct og_buffer *og_buffer = (struct og_buffer *)data; + + memcpy(og_buffer->data + og_buffer->len, buffer, size); + og_buffer->len += size; + + return 0; +} + +static int og_cmd_get_clients(json_t *element, struct og_msg_params *params, + char *buffer_reply) +{ + json_t *root, *array, *addr, *state, *object; + struct og_buffer og_buffer = { + .data = buffer_reply, + }; + int i; + + array = json_array(); + if (!array) + return -1; + + for (i = 0; i < MAXIMOS_CLIENTES; i++) { + if (tbsockets[i].ip[0] == '\0') + continue; + + object = json_object(); + if (!object) { + json_decref(array); + return -1; + } + addr = json_string(tbsockets[i].ip); + if (!addr) { + json_decref(object); + json_decref(array); + return -1; + } + json_object_set_new(object, "addr", addr); + + state = json_string(tbsockets[i].estado); + if (!state) { + json_decref(object); + json_decref(array); + return -1; + } + json_object_set_new(object, "state", state); + + json_array_append_new(array, object); + } + root = json_pack("{s:o}", "clients", array); + if (!root) { + json_decref(array); + return -1; + } + + json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); + json_decref(root); + + return 0; +} + +static int og_json_parse_target(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + + if (json_typeof(element) != JSON_OBJECT) { + return -1; + } + + json_object_foreach(element, key, value) { + if (!strcmp(key, "addr")) { + if (json_typeof(value) != JSON_STRING) + return -1; + + params->ips_array[params->ips_array_len] = + json_string_value(value); + + params->flags |= OG_REST_PARAM_ADDR; + } else if (!strcmp(key, "mac")) { + if (json_typeof(value) != JSON_STRING) + return -1; + + params->mac_array[params->ips_array_len] = + json_string_value(value); + + params->flags |= OG_REST_PARAM_MAC; + } + } + + return 0; +} + +static int og_json_parse_targets(json_t *element, struct og_msg_params *params) +{ + unsigned int i; + json_t *k; + int err; + + if (json_typeof(element) != JSON_ARRAY) + return -1; + + for (i = 0; i < json_array_size(element); i++) { + k = json_array_get(element, i); + + if (json_typeof(k) != JSON_OBJECT) + return -1; + + err = og_json_parse_target(k, params); + if (err < 0) + return err; + + params->ips_array_len++; + } + return 0; +} + +static int og_json_parse_type(json_t *element, struct og_msg_params *params) +{ + const char *type; + + if (json_typeof(element) != JSON_STRING) + return -1; + + params->wol_type = json_string_value(element); + + type = json_string_value(element); + if (!strcmp(type, "unicast")) + params->wol_type = "2"; + else if (!strcmp(type, "broadcast")) + params->wol_type = "1"; + + params->flags |= OG_REST_PARAM_WOL_TYPE; + + return 0; +} + +static int og_cmd_wol(json_t *element, struct og_msg_params *params) +{ + char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; + int ips_str_len = 0; + const char *msglog; + struct og_dbi *dbi; + int i = 0; + dbi_result result; + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_targets(value, params); + } else if (!strcmp(key, "type")) { + err = og_json_parse_type(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_MAC | + OG_REST_PARAM_WOL_TYPE)) + return -1; + + for (i = 0; i < params->ips_array_len; ++i) { + ips_str_len += snprintf(ips_str + ips_str_len, + sizeof(ips_str) - ips_str_len, + "'%s',", params->ips_array[i]); + } + ips_str[ips_str_len - 1] = '\0'; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT ordenadores.ip, ordenadores.mac, " + "aulas.netmask " + "FROM ordenadores " + "INNER JOIN aulas " + "ON ordenadores.idaula = aulas.idaula " + "WHERE ordenadores.ip IN (%s)", + ips_str); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + og_dbi_close(dbi); + return -1; + } + + for (i = 0; dbi_result_next_row(result); i++) { + params->ips_array[i] = dbi_result_get_string_copy(result, "ip"); + params->mac_array[i] = dbi_result_get_string_copy(result, "mac"); + params->netmask_array[i] = dbi_result_get_string_copy(result, "netmask"); + } + + dbi_result_free(result); + og_dbi_close(dbi); + + if (!Levanta((char **)params->ips_array, (char **)params->mac_array, + (char **)params->netmask_array, i, + (char *)params->wol_type)) + return -1; + + return 0; +} + +static int og_json_parse_run(json_t *element, struct og_msg_params *params) +{ + if (json_typeof(element) != JSON_STRING) + return -1; + + snprintf(params->run_cmd, sizeof(params->run_cmd), "%s", + json_string_value(element)); + + params->flags |= OG_REST_PARAM_RUN_CMD; + + return 0; +} + +static int og_cmd_run_post(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}, iph[4096] = {}; + int err = 0, len; + const char *key; + unsigned int i; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + else if (!strcmp(key, "run")) + err = og_json_parse_run(value, params); + else if (!strcmp(key, "echo")) { + err = og_json_parse_bool(value, ¶ms->echo); + params->flags |= OG_REST_PARAM_ECHO; + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_RUN_CMD | + OG_REST_PARAM_ECHO)) + return -1; + + for (i = 0; i < params->ips_array_len; i++) { + len = snprintf(iph + strlen(iph), sizeof(iph), "%s;", + params->ips_array[i]); + } + + if (params->echo) { + len = snprintf(buf, sizeof(buf), + "nfn=ConsolaRemota\riph=%s\rscp=%s\r", + iph, params->run_cmd); + } else { + len = snprintf(buf, sizeof(buf), + "nfn=EjecutarScript\riph=%s\rscp=%s\r", + iph, params->run_cmd); + } + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + if (!og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg)) + err = -1; + + og_msg_free(msg); + + if (err < 0) + return err; + + for (i = 0; i < params->ips_array_len; i++) { + char filename[4096]; + FILE *f; + + sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]); + f = fopen(filename, "wt"); + fclose(f); + } + + return 0; +} + +static int og_cmd_run_get(json_t *element, struct og_msg_params *params, + char *buffer_reply) +{ + struct og_buffer og_buffer = { + .data = buffer_reply, + }; + json_t *root, *value, *array; + const char *key; + unsigned int i; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + return err; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + array = json_array(); + if (!array) + return -1; + + for (i = 0; i < params->ips_array_len; i++) { + json_t *object, *output, *addr; + char data[4096] = {}; + char filename[4096]; + int fd, numbytes; + + sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]); + + fd = open(filename, O_RDONLY); + if (!fd) + return -1; + + numbytes = read(fd, data, sizeof(data)); + if (numbytes < 0) { + close(fd); + return -1; + } + data[sizeof(data) - 1] = '\0'; + close(fd); + + object = json_object(); + if (!object) { + json_decref(array); + return -1; + } + addr = json_string(params->ips_array[i]); + if (!addr) { + json_decref(object); + json_decref(array); + return -1; + } + json_object_set_new(object, "addr", addr); + + output = json_string(data); + if (!output) { + json_decref(object); + json_decref(array); + return -1; + } + json_object_set_new(object, "output", output); + + json_array_append_new(array, object); + } + + root = json_pack("{s:o}", "clients", array); + if (!root) + return -1; + + json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); + json_decref(root); + + return 0; +} + +static int og_cmd_session(json_t *element, struct og_msg_params *params) +{ + char buf[4096], iph[4096]; + int err = 0, len; + const char *key; + unsigned int i; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } + + if (err < 0) + return err; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION)) + return -1; + + for (i = 0; i < params->ips_array_len; i++) { + snprintf(iph + strlen(iph), sizeof(iph), "%s;", + params->ips_array[i]); + } + len = snprintf(buf, sizeof(buf), + "nfn=IniciarSesion\riph=%s\rdsk=%s\rpar=%s\r", + iph, params->disk, params->partition); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + if (!og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_APAGADO, msg)) + err = -1; + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_poweroff(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "Apagar", CLIENTE_OCUPADO); +} + +static int og_cmd_refresh(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "Actualizar", CLIENTE_APAGADO); +} + +static int og_cmd_reboot(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "Reiniciar", CLIENTE_OCUPADO); +} + +static int og_cmd_stop(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "Purgar", CLIENTE_APAGADO); +} + +static int og_cmd_hardware(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + return og_cmd_legacy_send(params, "InventarioHardware", + CLIENTE_OCUPADO); +} + +static int og_cmd_software(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } + else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=InventarioSoftware\rdsk=%s\rpar=%s\r", + params->disk, params->partition); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_create_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "code")) { + err = og_json_parse_string(value, ¶ms->code); + params->flags |= OG_REST_PARAM_CODE; + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_CODE | + OG_REST_PARAM_ID | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=CrearImagen\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r", + params->disk, params->partition, params->code, + params->id, params->name, params->repository); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_restore_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "type")) { + err = og_json_parse_string(value, ¶ms->type); + params->flags |= OG_REST_PARAM_TYPE; + } else if (!strcmp(key, "profile")) { + err = og_json_parse_string(value, ¶ms->profile); + params->flags |= OG_REST_PARAM_PROFILE; + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO | + OG_REST_PARAM_TYPE | + OG_REST_PARAM_PROFILE | + OG_REST_PARAM_ID)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=RestaurarImagen\ridi=%s\rdsk=%s\rpar=%s\rifs=%s\r" + "nci=%s\ripr=%s\rptc=%s\r", + params->id, params->disk, params->partition, + params->profile, params->name, + params->repository, params->type); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_setup(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "cache")) { + err = og_json_parse_string(value, ¶ms->cache); + params->flags |= OG_REST_PARAM_CACHE; + } else if (!strcmp(key, "cache_size")) { + err = og_json_parse_string(value, ¶ms->cache_size); + params->flags |= OG_REST_PARAM_CACHE_SIZE; + } else if (!strcmp(key, "partition_setup")) { + err = og_json_parse_partition_setup(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_CACHE | + OG_REST_PARAM_CACHE_SIZE | + OG_REST_PARAM_PART_0 | + OG_REST_PARAM_PART_1 | + OG_REST_PARAM_PART_2 | + OG_REST_PARAM_PART_3)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=Configurar\rdsk=%s\rcfg=dis=%s*che=%s*tch=%s!", + params->disk, params->disk, params->cache, params->cache_size); + + for (unsigned int i = 0; i < OG_PARTITION_MAX; ++i) { + const struct og_partition *part = ¶ms->partition_setup[i]; + + len += snprintf(buf + strlen(buf), sizeof(buf), + "par=%s*cpt=%s*sfi=%s*tam=%s*ope=%s%%", + part->number, part->code, part->filesystem, part->size, part->format); + } + + msg = og_msg_alloc(buf, len + 1); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) + return -1; + + og_cmd_legacy_send(params, "EjecutaComandosPendientes", CLIENTE_OCUPADO); + + return 0; +} + +static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "code")) { + err = og_json_parse_string(value, ¶ms->code); + params->flags |= OG_REST_PARAM_CODE; + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "sync_params")) { + err = og_json_parse_sync_params(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_CODE | + OG_REST_PARAM_ID | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO | + OG_REST_PARAM_SYNC_SYNC | + OG_REST_PARAM_SYNC_DIFF | + OG_REST_PARAM_SYNC_REMOVE | + OG_REST_PARAM_SYNC_COMPRESS | + OG_REST_PARAM_SYNC_CLEANUP | + OG_REST_PARAM_SYNC_CACHE | + OG_REST_PARAM_SYNC_CLEANUP_CACHE | + OG_REST_PARAM_SYNC_REMOVE_DST)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r" + "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r" + "cpc=%s\rbpc=%s\rnba=%s\r", + params->disk, params->partition, params->code, params->id, + params->name, params->repository, params->sync_setup.sync, + params->sync_setup.diff, params->sync_setup.remove, + params->sync_setup.compress, params->sync_setup.cleanup, + params->sync_setup.cache, params->sync_setup.cleanup_cache, + params->sync_setup.remove_dst); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) + err = og_json_parse_clients(value, params); + else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "sync_params")) { + err = og_json_parse_sync_params(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_ID | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO | + OG_REST_PARAM_SYNC_SYNC | + OG_REST_PARAM_SYNC_PATH | + OG_REST_PARAM_SYNC_DIFF | + OG_REST_PARAM_SYNC_DIFF_ID | + OG_REST_PARAM_SYNC_DIFF_NAME | + OG_REST_PARAM_SYNC_REMOVE | + OG_REST_PARAM_SYNC_COMPRESS | + OG_REST_PARAM_SYNC_CLEANUP | + OG_REST_PARAM_SYNC_CACHE | + OG_REST_PARAM_SYNC_CLEANUP_CACHE | + OG_REST_PARAM_SYNC_REMOVE_DST)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r" + "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r" + "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r", + params->disk, params->partition, params->id, params->name, + params->sync_setup.path, params->repository, params->sync_setup.diff_id, + params->sync_setup.diff_name, params->sync_setup.sync, + params->sync_setup.diff, params->sync_setup.remove_dst, + params->sync_setup.compress, params->sync_setup.cleanup, + params->sync_setup.cache, params->sync_setup.cleanup_cache, + params->sync_setup.remove_dst); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "profile")) { + err = og_json_parse_string(value, ¶ms->profile); + params->flags |= OG_REST_PARAM_PROFILE; + } else if (!strcmp(key, "type")) { + err = og_json_parse_string(value, ¶ms->type); + params->flags |= OG_REST_PARAM_TYPE; + } else if (!strcmp(key, "sync_params")) { + err = og_json_parse_sync_params(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_ID | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO | + OG_REST_PARAM_PROFILE | + OG_REST_PARAM_TYPE | + OG_REST_PARAM_SYNC_PATH | + OG_REST_PARAM_SYNC_METHOD | + OG_REST_PARAM_SYNC_SYNC | + OG_REST_PARAM_SYNC_DIFF | + OG_REST_PARAM_SYNC_REMOVE | + OG_REST_PARAM_SYNC_COMPRESS | + OG_REST_PARAM_SYNC_CLEANUP | + OG_REST_PARAM_SYNC_CACHE | + OG_REST_PARAM_SYNC_CLEANUP_CACHE | + OG_REST_PARAM_SYNC_REMOVE_DST)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r" + "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r" + "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r", + params->disk, params->partition, params->id, params->name, + params->repository, params->profile, params->sync_setup.path, + params->sync_setup.method, params->sync_setup.sync, params->type, + params->sync_setup.diff, params->sync_setup.remove, + params->sync_setup.compress, params->sync_setup.cleanup, + params->sync_setup.cache, params->sync_setup.cleanup_cache, + params->sync_setup.remove_dst); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params) +{ + char buf[4096] = {}; + int err = 0, len; + const char *key; + json_t *value; + TRAMA *msg; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "clients")) { + err = og_json_parse_clients(value, params); + } else if (!strcmp(key, "disk")) { + err = og_json_parse_string(value, ¶ms->disk); + params->flags |= OG_REST_PARAM_DISK; + } else if (!strcmp(key, "partition")) { + err = og_json_parse_string(value, ¶ms->partition); + params->flags |= OG_REST_PARAM_PARTITION; + } else if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "repository")) { + err = og_json_parse_string(value, ¶ms->repository); + params->flags |= OG_REST_PARAM_REPO; + } else if (!strcmp(key, "profile")) { + err = og_json_parse_string(value, ¶ms->profile); + params->flags |= OG_REST_PARAM_PROFILE; + } else if (!strcmp(key, "type")) { + err = og_json_parse_string(value, ¶ms->type); + params->flags |= OG_REST_PARAM_TYPE; + } else if (!strcmp(key, "sync_params")) { + err = og_json_parse_sync_params(value, params); + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | + OG_REST_PARAM_DISK | + OG_REST_PARAM_PARTITION | + OG_REST_PARAM_ID | + OG_REST_PARAM_NAME | + OG_REST_PARAM_REPO | + OG_REST_PARAM_PROFILE | + OG_REST_PARAM_TYPE | + OG_REST_PARAM_SYNC_DIFF_ID | + OG_REST_PARAM_SYNC_DIFF_NAME | + OG_REST_PARAM_SYNC_PATH | + OG_REST_PARAM_SYNC_METHOD | + OG_REST_PARAM_SYNC_SYNC | + OG_REST_PARAM_SYNC_DIFF | + OG_REST_PARAM_SYNC_REMOVE | + OG_REST_PARAM_SYNC_COMPRESS | + OG_REST_PARAM_SYNC_CLEANUP | + OG_REST_PARAM_SYNC_CACHE | + OG_REST_PARAM_SYNC_CLEANUP_CACHE | + OG_REST_PARAM_SYNC_REMOVE_DST)) + return -1; + + len = snprintf(buf, sizeof(buf), + "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r" + "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r" + "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r" + "nba=%s\r", + params->disk, params->partition, params->id, params->name, + params->repository, params->profile, params->sync_setup.diff_id, + params->sync_setup.diff_name, params->sync_setup.path, + params->sync_setup.method, params->sync_setup.sync, params->type, + params->sync_setup.diff, params->sync_setup.remove, + params->sync_setup.compress, params->sync_setup.cleanup, + params->sync_setup.cache, params->sync_setup.cleanup_cache, + params->sync_setup.remove_dst); + + msg = og_msg_alloc(buf, len); + if (!msg) + return -1; + + og_send_cmd((char **)params->ips_array, params->ips_array_len, + CLIENTE_OCUPADO, msg); + + og_msg_free(msg); + + return 0; +} + +static int og_client_method_not_found(struct og_client *cli) +{ + /* To meet RFC 7231, this function MUST generate an Allow header field + * containing the correct methods. For example: "Allow: POST\r\n" + */ + char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n" + "Content-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +static int og_client_bad_request(struct og_client *cli) +{ + char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +static int og_client_not_found(struct og_client *cli) +{ + char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +static int og_client_not_authorized(struct og_client *cli) +{ + char buf[] = "HTTP/1.1 401 Unauthorized\r\n" + "WWW-Authenticate: Basic\r\n" + "Content-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +static int og_server_internal_error(struct og_client *cli) +{ + char buf[] = "HTTP/1.1 500 Internal Server Error\r\n" + "Content-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +static int og_client_payload_too_large(struct og_client *cli) +{ + char buf[] = "HTTP/1.1 413 Payload Too Large\r\n" + "Content-Length: 0\r\n\r\n"; + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return -1; +} + +#define OG_MSG_RESPONSE_MAXLEN 65536 + +static int og_client_ok(struct og_client *cli, char *buf_reply) +{ + char buf[OG_MSG_RESPONSE_MAXLEN] = {}; + int err = 0, len; + + len = snprintf(buf, sizeof(buf), + "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s", + strlen(buf_reply), buf_reply); + if (len >= (int)sizeof(buf)) + err = og_server_internal_error(cli); + + send(og_client_socket(cli), buf, strlen(buf), 0); + + return err; +} + +enum og_rest_method { + OG_METHOD_GET = 0, + OG_METHOD_POST, +}; + +static int og_client_state_process_payload_rest(struct og_client *cli) +{ + char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {}; + struct og_msg_params params = {}; + enum og_rest_method method; + const char *cmd, *body; + json_error_t json_err; + json_t *root = NULL; + int err = 0; + + syslog(LOG_DEBUG, "%s:%hu %.32s ...\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port), cli->buf); + + if (!strncmp(cli->buf, "GET", strlen("GET"))) { + method = OG_METHOD_GET; + cmd = cli->buf + strlen("GET") + 2; + } else if (!strncmp(cli->buf, "POST", strlen("POST"))) { + method = OG_METHOD_POST; + cmd = cli->buf + strlen("POST") + 2; + } else + return og_client_method_not_found(cli); + + body = strstr(cli->buf, "\r\n\r\n") + 4; + + if (strcmp(cli->auth_token, auth_token)) { + syslog(LOG_ERR, "wrong Authentication key\n"); + return og_client_not_authorized(cli); + } + + if (cli->content_length) { + root = json_loads(body, 0, &json_err); + if (!root) { + syslog(LOG_ERR, "malformed json line %d: %s\n", + json_err.line, json_err.text); + return og_client_not_found(cli); + } + } + + if (!strncmp(cmd, "clients", strlen("clients"))) { + if (method != OG_METHOD_POST && + method != OG_METHOD_GET) + return og_client_method_not_found(cli); + + if (method == OG_METHOD_POST && !root) { + syslog(LOG_ERR, "command clients with no payload\n"); + return og_client_bad_request(cli); + } + switch (method) { + case OG_METHOD_POST: + err = og_cmd_post_clients(root, ¶ms); + break; + case OG_METHOD_GET: + err = og_cmd_get_clients(root, ¶ms, buf_reply); + break; + } + } else if (!strncmp(cmd, "wol", strlen("wol"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command wol with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_wol(root, ¶ms); + } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command run with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_run_post(root, ¶ms); + } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command output with no payload\n"); + return og_client_bad_request(cli); + } + + err = og_cmd_run_get(root, ¶ms, buf_reply); + } else if (!strncmp(cmd, "session", strlen("session"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command session with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_session(root, ¶ms); + } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command poweroff with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_poweroff(root, ¶ms); + } else if (!strncmp(cmd, "reboot", strlen("reboot"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command reboot with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_reboot(root, ¶ms); + } else if (!strncmp(cmd, "stop", strlen("stop"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command stop with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_stop(root, ¶ms); + } else if (!strncmp(cmd, "refresh", strlen("refresh"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command refresh with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_refresh(root, ¶ms); + } else if (!strncmp(cmd, "hardware", strlen("hardware"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command hardware with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_hardware(root, ¶ms); + } else if (!strncmp(cmd, "software", strlen("software"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command software with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_software(root, ¶ms); + } else if (!strncmp(cmd, "image/create/basic", + strlen("image/create/basic"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_create_basic_image(root, ¶ms); + } else if (!strncmp(cmd, "image/create/incremental", + strlen("image/create/incremental"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_create_incremental_image(root, ¶ms); + } else if (!strncmp(cmd, "image/create", strlen("image/create"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_create_image(root, ¶ms); + } else if (!strncmp(cmd, "image/restore/basic", + strlen("image/restore/basic"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_restore_basic_image(root, ¶ms); + } else if (!strncmp(cmd, "image/restore/incremental", + strlen("image/restore/incremental"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_restore_incremental_image(root, ¶ms); + } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_restore_image(root, ¶ms); + } else if (!strncmp(cmd, "setup", strlen("setup"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_setup(root, ¶ms); + } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command create with no payload\n"); + return og_client_bad_request(cli); + } + + err = og_cmd_run_schedule(root, ¶ms); + } else { + syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd); + err = og_client_not_found(cli); + } + + if (root) + json_decref(root); + + if (err < 0) + return og_client_bad_request(cli); + + err = og_client_ok(cli, buf_reply); + if (err < 0) { + syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + } + + return err; +} + +static int og_client_state_recv_hdr_rest(struct og_client *cli) +{ + char *ptr; + + ptr = strstr(cli->buf, "\r\n\r\n"); + if (!ptr) + return 0; + + cli->msg_len = ptr - cli->buf + 4; + + ptr = strstr(cli->buf, "Content-Length: "); + if (ptr) { + sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length); + if (cli->content_length < 0) + return -1; + cli->msg_len += cli->content_length; + } + + ptr = strstr(cli->buf, "Authorization: "); + if (ptr) + sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token); + + return 1; +} + +static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events) +{ + struct og_client *cli; + int ret; + + cli = container_of(io, struct og_client, io); + + if (events & EV_ERROR) { + syslog(LOG_ERR, "unexpected error event from client %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + goto close; + } + + ret = recv(io->fd, cli->buf + cli->buf_len, + sizeof(cli->buf) - cli->buf_len, 0); + if (ret <= 0) { + if (ret < 0) { + syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), + strerror(errno)); + } else { + syslog(LOG_DEBUG, "closed connection by %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); + } + goto close; + } + + if (cli->keepalive_idx >= 0) + return; + + ev_timer_again(loop, &cli->timer); + + cli->buf_len += ret; + if (cli->buf_len >= sizeof(cli->buf)) { + syslog(LOG_ERR, "client request from %s:%hu is too long\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); + og_client_payload_too_large(cli); + goto close; + } + + switch (cli->state) { + case OG_CLIENT_RECEIVING_HEADER: + if (cli->rest) + ret = og_client_state_recv_hdr_rest(cli); + else + ret = og_client_state_recv_hdr(cli); + + if (ret < 0) + goto close; + if (!ret) + return; + + cli->state = OG_CLIENT_RECEIVING_PAYLOAD; + /* Fall through. */ + case OG_CLIENT_RECEIVING_PAYLOAD: + /* Still not enough data to process request. */ + if (cli->buf_len < cli->msg_len) + return; + + cli->state = OG_CLIENT_PROCESSING_REQUEST; + /* fall through. */ + case OG_CLIENT_PROCESSING_REQUEST: + if (cli->rest) { + ret = og_client_state_process_payload_rest(cli); + if (ret < 0) { + syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + } + } else { + ret = og_client_state_process_payload(cli); + } + if (ret < 0) + goto close; + + if (cli->keepalive_idx < 0) { + syslog(LOG_DEBUG, "server closing connection to %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); + goto close; + } else { + syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n", + inet_ntoa(cli->addr.sin_addr), + ntohs(cli->addr.sin_port)); + og_client_keepalive(loop, cli); + og_client_reset_state(cli); + } + break; + default: + syslog(LOG_ERR, "unknown state, critical internal error\n"); + goto close; + } + return; +close: + ev_timer_stop(loop, &cli->timer); + og_client_release(loop, cli); +} + +static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events) +{ + struct og_client *cli; + + cli = container_of(timer, struct og_client, timer); + if (cli->keepalive_idx >= 0) { + ev_timer_again(loop, &cli->timer); + return; + } + syslog(LOG_ERR, "timeout request for client %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); + + og_client_release(loop, cli); +} + +static int socket_s, socket_rest; + +static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io, + int events) +{ + struct sockaddr_in client_addr; + socklen_t addrlen = sizeof(client_addr); + struct og_client *cli; + int client_sd; + + if (events & EV_ERROR) + return; + + client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen); + if (client_sd < 0) { + syslog(LOG_ERR, "cannot accept client connection\n"); + return; + } + + cli = (struct og_client *)calloc(1, sizeof(struct og_client)); + if (!cli) { + close(client_sd); + return; + } + memcpy(&cli->addr, &client_addr, sizeof(client_addr)); + cli->keepalive_idx = -1; + + if (io->fd == socket_rest) + cli->rest = true; + + syslog(LOG_DEBUG, "connection from client %s:%hu\n", + inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); + + ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ); + ev_io_start(loop, &cli->io); + ev_timer_init(&cli->timer, og_client_timer_cb, OG_CLIENT_TIMEOUT, 0.); + ev_timer_start(loop, &cli->timer); +} + +static int og_socket_server_init(const char *port) +{ + struct sockaddr_in local; + int sd, on = 1; + + sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sd < 0) { + syslog(LOG_ERR, "cannot create main socket\n"); + return -1; + } + setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int)); + + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_family = AF_INET; + local.sin_port = htons(atoi(port)); + + if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) { + close(sd); + syslog(LOG_ERR, "cannot bind socket\n"); + return -1; + } + + listen(sd, 250); + + return sd; +} + +int main(int argc, char *argv[]) +{ + struct ev_io ev_io_server, ev_io_server_rest; + struct ev_loop *loop = ev_default_loop(0); + int i; + + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + exit(EXIT_FAILURE); + + openlog("ogAdmServer", LOG_PID, LOG_DAEMON); + + /*-------------------------------------------------------------------------------------------------------- + Validación de parámetros de ejecución y lectura del fichero de configuración del servicio + ---------------------------------------------------------------------------------------------------------*/ + if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución + exit(EXIT_FAILURE); + + if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion + exit(EXIT_FAILURE); + } + + /*-------------------------------------------------------------------------------------------------------- + // Inicializa array de información de los clientes + ---------------------------------------------------------------------------------------------------------*/ + for (i = 0; i < MAXIMOS_CLIENTES; i++) { + tbsockets[i].ip[0] = '\0'; + tbsockets[i].cli = NULL; + } + /*-------------------------------------------------------------------------------------------------------- + Creación y configuración del socket del servicio + ---------------------------------------------------------------------------------------------------------*/ + socket_s = og_socket_server_init(puerto); + if (socket_s < 0) + exit(EXIT_FAILURE); + + ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ); + ev_io_start(loop, &ev_io_server); + + socket_rest = og_socket_server_init("8888"); + if (socket_rest < 0) + exit(EXIT_FAILURE); + + ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ); + ev_io_start(loop, &ev_io_server_rest); + + infoLog(1); // Inicio de sesión + + /* old log file has been deprecated. */ + og_log(97, false); + + syslog(LOG_INFO, "Waiting for connections\n"); + + while (1) + ev_loop(loop, 0); + + exit(EXIT_SUCCESS); +} diff --git a/native/Sources/Services/ogAdmServer/sources/ogAdmServer.h b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.h new file mode 100644 index 0000000..a8128c1 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.h @@ -0,0 +1,60 @@ +// ******************************************************************************************************** +// Servicio: ogAdmServer +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmServer.h +// Descripción: Este fichero implementa el servicio de administración general del sistema +// ******************************************************************************************************** +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ogAdmLib.h" +// ________________________________________________________________________________________________________ +// Variables globales +// ________________________________________________________________________________________________________ +char servidoradm[LONPRM]; // Dirección IP del servidor de administración +char puerto[LONPRM]; // Puerto de comunicación + +struct og_client; + +typedef struct{ // Estructura usada para guardar información de los clientes + char ip[LONIP]; // IP del cliente + char estado[4]; // Tipo de Sistema Operativo en que se encuentra el cliente + struct og_client *cli; +}SOCKETCL; +SOCKETCL tbsockets[MAXIMOS_CLIENTES]; + +struct og_dbi; + +bool registraCliente(char *); +bool procesoInclusionClienteWinLnx(int socket, TRAMA*,int*,char*); +bool procesoInclusionCliente(struct og_client *, TRAMA*); +bool clienteExistente(char *,int *); +bool clienteDisponible(char *,int *); +bool actualizaConfiguracion(struct og_dbi *,char* ,int); +bool recorreProcedimientos(struct og_dbi *,char* ,FILE*,char*); +bool buscaComandos(char *,TRAMA *,int *); +bool respuestaConsola(int socket, TRAMA *,int); +bool enviaComando(TRAMA *ptrTrama,const char*); +bool Levanta(char**, char**, char**, int, char*); +bool WakeUp(int,char*,char*,char*,char*); +void PasaHexBin(char *,char *); +bool actualizaCreacionImagen(struct og_dbi *,char*,char*,char*,char*,char*,char*); +bool actualizaRestauracionImagen(struct og_dbi *,char*,char*,char*,char*,char*); +bool actualizaHardware(struct og_dbi *dbi, char* ,char*,char*,char*); +bool cuestionPerfilHardware(struct og_dbi *dbi,char*,char*,int,char*,char*,int *,int); +bool actualizaSoftware(struct og_dbi *, char* , char* , char*,char*,char*); +bool cuestionPerfilSoftware(struct og_dbi *, char*, char*,int,int,char*,char*,char*,int *,int); + +int checkDato(struct og_dbi *,char*,const char*,const char*,const char*); diff --git a/native/Sources/Services/ogAdmServer/sources/ogAdmServer.o b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.o new file mode 100644 index 0000000..1da52d8 Binary files /dev/null and b/native/Sources/Services/ogAdmServer/sources/ogAdmServer.o differ diff --git a/native/Sources/Services/ogAdmServer/tests/clients.json b/native/Sources/Services/ogAdmServer/tests/clients.json new file mode 100644 index 0000000..01672ed --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/clients.json @@ -0,0 +1 @@ +curl -X GET http://127.0.0.1:8888/clients diff --git a/native/Sources/Services/ogAdmServer/tests/config/ogAdmServer.cfg b/native/Sources/Services/ogAdmServer/tests/config/ogAdmServer.cfg new file mode 100644 index 0000000..41d812b --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/config/ogAdmServer.cfg @@ -0,0 +1,8 @@ +ServidorAdm=localhost +PUERTO=2008 +USUARIO=test-db +PASSWORD=test-db +datasource=localhost +CATALOG=test-db +INTERFACE=eth1 +APITOKEN=07b3bfe728954619b58f0107ad73acc1 diff --git a/native/Sources/Services/ogAdmServer/tests/create_basic_image.json b/native/Sources/Services/ogAdmServer/tests/create_basic_image.json new file mode 100644 index 0000000..8000219 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/create_basic_image.json @@ -0,0 +1 @@ +{"clients":["192.168.56.11"],"disk":"1","partition":"1","code":"131","id":"8","name":"debianbasica","repository":"192.168.56.10","sync_params":{"sync":"1","diff":"0","remove":"1","compress":"0","cleanup":"0","cache":"0","cleanup_cache":"0","remove_dst":"0"}} diff --git a/native/Sources/Services/ogAdmServer/tests/create_image.json b/native/Sources/Services/ogAdmServer/tests/create_image.json new file mode 100644 index 0000000..bd4ab21 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/create_image.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1" ], "disk" : "1", "partition" : "1", "code" : "1", "id" : "1", "name" : "test", "repository" : "192.168.2.4" } diff --git a/native/Sources/Services/ogAdmServer/tests/create_incremental_image.json b/native/Sources/Services/ogAdmServer/tests/create_incremental_image.json new file mode 100644 index 0000000..94b3a4d --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/create_incremental_image.json @@ -0,0 +1 @@ +{"clients":["192.168.56.11"], "disk":"1", "partition":"1", "id":"3", "name":"basica1", "repository":"192.168.56.10", "sync_params":{"sync":"1", "path":"", "diff":"0", "diff_id":"4", "diff_name":"p2", "remove":"1", "compress":"0", "cleanup":"0", "cache":"0", "cleanup_cache":"0", "remove_dst":"0"}} diff --git a/native/Sources/Services/ogAdmServer/tests/post_clients.json b/native/Sources/Services/ogAdmServer/tests/post_clients.json new file mode 100644 index 0000000..4667303 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/post_clients.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ] } diff --git a/native/Sources/Services/ogAdmServer/tests/post_shell_output.json b/native/Sources/Services/ogAdmServer/tests/post_shell_output.json new file mode 100644 index 0000000..1badfed --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/post_shell_output.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ]} diff --git a/native/Sources/Services/ogAdmServer/tests/post_shell_run.json b/native/Sources/Services/ogAdmServer/tests/post_shell_run.json new file mode 100644 index 0000000..1449d05 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/post_shell_run.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ], "run" : "ls" } diff --git a/native/Sources/Services/ogAdmServer/tests/poweroff.json b/native/Sources/Services/ogAdmServer/tests/poweroff.json new file mode 100644 index 0000000..4667303 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/poweroff.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ] } diff --git a/native/Sources/Services/ogAdmServer/tests/reboot.json b/native/Sources/Services/ogAdmServer/tests/reboot.json new file mode 100644 index 0000000..4667303 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/reboot.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ] } diff --git a/native/Sources/Services/ogAdmServer/tests/restore_basic_image.json b/native/Sources/Services/ogAdmServer/tests/restore_basic_image.json new file mode 100644 index 0000000..255507c --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/restore_basic_image.json @@ -0,0 +1 @@ +{"clients":["192.168.56.11"],"disk":"1","partition":"1","id":"9","name":"test","repository":"192.168.56.10","profile":"17","type":"UNICAST","sync_params":{"path":"","method":"1","sync":"1","diff":"0","remove":"1","compress":"0","cleanup":"0","cache":"0","cleanup_cache":"0","remove_dst":"0"}} diff --git a/native/Sources/Services/ogAdmServer/tests/restore_image.json b/native/Sources/Services/ogAdmServer/tests/restore_image.json new file mode 100644 index 0000000..bf2982a --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/restore_image.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.56.11" ], "disk" : "1", "partition" : "1", "name" : "test", "repository" : "192.168.56.10", "type" : "UNICAST", "profile": "1", "id": "1"} diff --git a/native/Sources/Services/ogAdmServer/tests/restore_incremental_image.json b/native/Sources/Services/ogAdmServer/tests/restore_incremental_image.json new file mode 100644 index 0000000..66dfd0a --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/restore_incremental_image.json @@ -0,0 +1 @@ +{"clients":["192.168.56.11"],"disk":"1","partition":"1","id":"9","name":"test","repository":"192.168.56.10","profile":"17","type":"UNICAST","sync_params":{"diff_id":"1","diff_name":"test","path":"","method":"1","sync":"1","diff":"0","remove":"1","compress":"0","cleanup":"0","cache":"0","cleanup_cache":"0","remove_dst":"0"}} diff --git a/native/Sources/Services/ogAdmServer/tests/run-tests.py b/native/Sources/Services/ogAdmServer/tests/run-tests.py new file mode 100755 index 0000000..1a59a34 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/run-tests.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import subprocess, glob, os + +sql_data = "INSERT INTO aulas (nombreaula, idcentro, urlfoto, grupoid, ubicacion, puestos, modomul, ipmul, pormul, velmul, router, netmask, ntp, dns, proxy, modp2p, timep2p) VALUES ('Aula virtual', 1, 'aula.jpg', 0, 'Despliegue virtual con Vagrant.', 5, 2, '239.194.2.11', 9000, 70, '192.168.56.1', '255.255.255.0', '', '', '', 'peer', 30); INSERT INTO ordenadores (nombreordenador, ip, mac, idaula, idrepositorio, idperfilhard, idmenu, idproautoexec, grupoid, router, mascara, arranque, netiface, netdriver, fotoord) VALUES ('pc2', '192.168.2.1', '0800270E6501', 1, 1, 0, 0, 0, 0, '192.168.56.1', '255.255.255.0', '00unknown', 'eth0', 'generic', 'fotoordenador.gif'), ('pc2', '192.168.2.2', '0800270E6502', 1, 1, 0, 0, 0, 0, '192.168.56.1', '255.255.255.0', '00unknown', 'eth0', 'generic', 'fotoordenador.gif');" + +sql_create_user = "CREATE USER 'test-db'@'hostname'; GRANT ALL PRIVILEGES ON *.* To 'test-db'@'hostname' IDENTIFIED BY 'test-db';" + +sql_delete_user = "DROP USER 'test-db'@'hostname';" + +def start_mysql(): + + subprocess.run(['mysqladmin', 'drop', '-f', 'test-db'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(['mysqladmin', 'create', 'test-db']) + subprocess.run('mysql --default-character-set=utf8 test-db < ../../../../Database/ogAdmBD.sql', shell=True) + subprocess.run(['mysql', '-D', 'test-db', '-e', sql_data]) + subprocess.run(['mysql', '-D', 'test-db', '-e', sql_create_user]) + +def stop_mysql(): + + subprocess.run(['mysql', '-D', 'test-db', '-e', sql_delete_user]) + subprocess.run(['mysqladmin', 'drop', '-f', 'test-db']) + +if os.getuid() is not 0: + print('You need to be root to run these tests :-)') + exit() + +if os.path.isfile('../ogAdmServer') is not True: + print('You need to build the ogAdmServer binary to run these tests :-)') + exit() + +start_mysql(); + +subprocess.Popen(['../ogAdmServer', '-f', 'config/ogAdmServer.cfg']) + +subprocess.run('python3 -m unittest discover -s units -v', shell=True) + +stop_mysql(); + +subprocess.run(['pkill', 'ogAdmServer']) diff --git a/native/Sources/Services/ogAdmServer/tests/run-tests.sh b/native/Sources/Services/ogAdmServer/tests/run-tests.sh new file mode 100755 index 0000000..893e026 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/run-tests.sh @@ -0,0 +1,22 @@ +API_KEY="07b3bfe728954619b58f0107ad73acc1" + +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/clients -d @post_clients.json +curl -X GET -H "Authorization: $API_KEY" http://127.0.0.1:8888/clients +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/wol -d @wol.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/shell/run -d @post_shell_run.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/shell/output -d @post_shell_output.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/session -d @session.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/poweroff -d @poweroff.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/reboot -d @reboot.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/stop -d @stop.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/refresh -d @refresh.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/hardware -d @post_clients.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/software -d @post_clients.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/create -d @create_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/restore -d @restore_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/setup -d @setup_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/create/basic -d @create_basic_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/create/incremental -d @create_incremental_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/restore/basic -d @restore_basic_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/image/restore/incremental -d @restore_incremental_image.json +curl -X POST -H "Authorization: $API_KEY" http://127.0.0.1:8888/run/schedule -d @run_schedule.json diff --git a/native/Sources/Services/ogAdmServer/tests/run_schedule.json b/native/Sources/Services/ogAdmServer/tests/run_schedule.json new file mode 100644 index 0000000..60a1034 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/run_schedule.json @@ -0,0 +1 @@ +{"clients":["192.168.56.11"]} diff --git a/native/Sources/Services/ogAdmServer/tests/session.json b/native/Sources/Services/ogAdmServer/tests/session.json new file mode 100644 index 0000000..1b473c4 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/session.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ], "disk" : "0", "partition" : "1"} diff --git a/native/Sources/Services/ogAdmServer/tests/setup_image.json b/native/Sources/Services/ogAdmServer/tests/setup_image.json new file mode 100644 index 0000000..0135e20 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/setup_image.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.56.11" ], "disk" : "1", "cache" : "1", "cache_size" : "0", "partition_setup": [{"partition": "1", "code": "LINUX", "filesystem": "EMPTY", "size": "498688", "format": "0"}, {"partition": "2", "code": "LINUX-SWAP", "filesystem": "EMPTY", "size": "199987", "format": "0"}, {"partition": "3", "code": "LINUX", "filesystem": "EMPTY", "size": "31053824", "format": "0"}, {"partition": "4", "code": "EMPTY", "filesystem": "EMPTY", "size": "0", "format": "0"}]} diff --git a/native/Sources/Services/ogAdmServer/tests/stop.json b/native/Sources/Services/ogAdmServer/tests/stop.json new file mode 100644 index 0000000..4667303 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/stop.json @@ -0,0 +1 @@ +{ "clients" : [ "192.168.2.1", "192.168.2.2" ] } diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0001_get_clients.py b/native/Sources/Services/ogAdmServer/tests/units/test_0001_get_clients.py new file mode 100644 index 0000000..218b41a --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0001_get_clients.py @@ -0,0 +1,19 @@ +import requests +import unittest + +class TestGetClientsMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/clients' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 200) + + def test_post_without_data(self): + returned = requests.post(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 400) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0002_post_clients.py b/native/Sources/Services/ogAdmServer/tests/units/test_0002_post_clients.py new file mode 100644 index 0000000..3e0d4e5 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0002_post_clients.py @@ -0,0 +1,24 @@ +import requests +import unittest + +class TestPostClientsMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/clients' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0003_post_wol.py b/native/Sources/Services/ogAdmServer/tests/units/test_0003_post_wol.py new file mode 100644 index 0000000..5c8c012 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0003_post_wol.py @@ -0,0 +1,34 @@ +import requests +import unittest + +class TestPostWolMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/wol' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'type' : 'broadcast', 'clients' : [ { 'addr' : '192.168.2.1', + 'mac' : '00AABBCCDD01' } ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0004_post_shell_run.py b/native/Sources/Services/ogAdmServer/tests/units/test_0004_post_shell_run.py new file mode 100644 index 0000000..11779da --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0004_post_shell_run.py @@ -0,0 +1,35 @@ +import requests +import unittest + +class TestPostShellRunMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/shell/run' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'run' : 'ls', + 'echo': True} + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0005_post_shell_output.py b/native/Sources/Services/ogAdmServer/tests/units/test_0005_post_shell_output.py new file mode 100644 index 0000000..dec9ccd --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0005_post_shell_output.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostShellOutputMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/shell/output' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0006_post_session.py b/native/Sources/Services/ogAdmServer/tests/units/test_0006_post_session.py new file mode 100644 index 0000000..ba6179f --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0006_post_session.py @@ -0,0 +1,34 @@ +import requests +import unittest + +class TestPostSessionMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/session' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk' : '0', 'partition' : '1'} + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0007_post_poweroff.py b/native/Sources/Services/ogAdmServer/tests/units/test_0007_post_poweroff.py new file mode 100644 index 0000000..3c26265 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0007_post_poweroff.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostPoweroffMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/poweroff' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0008_post_reboot.py b/native/Sources/Services/ogAdmServer/tests/units/test_0008_post_reboot.py new file mode 100644 index 0000000..6705e87 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0008_post_reboot.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostRebootMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/reboot' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0009_post_stop.py b/native/Sources/Services/ogAdmServer/tests/units/test_0009_post_stop.py new file mode 100644 index 0000000..68b1b7c --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0009_post_stop.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostStopMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/stop' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0010_post_refresh.py b/native/Sources/Services/ogAdmServer/tests/units/test_0010_post_refresh.py new file mode 100644 index 0000000..0df3c60 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0010_post_refresh.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostRefreshMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/refresh' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0011_post_hardware.py b/native/Sources/Services/ogAdmServer/tests/units/test_0011_post_hardware.py new file mode 100644 index 0000000..1f3e160 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0011_post_hardware.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostHardwareMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/hardware' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0012_post_software.py b/native/Sources/Services/ogAdmServer/tests/units/test_0012_post_software.py new file mode 100644 index 0000000..3a00d46 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0012_post_software.py @@ -0,0 +1,35 @@ +import requests +import unittest + +class TestPostSoftwareMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/software' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk' : '0', + 'partition' : '1' } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0013_nonexistent.py b/native/Sources/Services/ogAdmServer/tests/units/test_0013_nonexistent.py new file mode 100644 index 0000000..b2e908c --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0013_nonexistent.py @@ -0,0 +1,30 @@ +import requests +import unittest + +class TestPostNonexistentMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/nonexistent' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.wrong_headers = {'Authorization' : + 'WrongWrongWrongWrongWrongWrongWr'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 404) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 404) + + def test_post_unauthenticated(self): + returned = requests.post(self.url, headers=self.wrong_headers) + self.assertEqual(returned.status_code, 401) + + def test_post_without_json(self): + returned = requests.post(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 404) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0014_big_request.py b/native/Sources/Services/ogAdmServer/tests/units/test_0014_big_request.py new file mode 100644 index 0000000..5e5e2d7 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0014_big_request.py @@ -0,0 +1,19 @@ +import requests +import unittest + +MAX_REQ_SIZE = 4096 + +class TestBigRequest(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/clients' + self.data = 'X' * MAX_REQ_SIZE + + def test_post(self): + with self.assertRaises(requests.exceptions.ConnectionError) as context: + requests.post(self.url, data=self.data) + + self.assertTrue('Connection reset by peer' in str(context.exception)) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0015_wrong_headers.py b/native/Sources/Services/ogAdmServer/tests/units/test_0015_wrong_headers.py new file mode 100644 index 0000000..8a35321 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0015_wrong_headers.py @@ -0,0 +1,29 @@ +import requests +import unittest + +class TestPostWrongHeaders(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/clients' + self.too_large_content_length_headers = {'Authorization' : + '07b3bfe728954619b58f0107ad73acc1', 'Content-Length' : + '999999999999999999999999999999999999999999999999999999999'} + self.too_large_auth_headers = {'Authorization' : + 'TooLongoTooLongTooLongTooLongTooLongTooLongTooLongTooLong' + 'TooLongoTooLongTooLongTooLongTooLongTooLongTooLongTooLong' + 'TooLongoTooLongTooLongTooLongTooLongTooLongTooLongTooLong'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post_too_large_content(self): + with self.assertRaises(requests.exceptions.ConnectionError) as context: + returned = requests.post(self.url, + headers=self.too_large_content_length_headers) + + self.assertTrue('Connection aborted' in str(context.exception)) + + def test_post_too_large_auth(self): + returned = requests.post(self.url, headers=self.too_large_auth_headers) + self.assertEqual(returned.status_code, 401) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0016_post_image_create.py b/native/Sources/Services/ogAdmServer/tests/units/test_0016_post_image_create.py new file mode 100644 index 0000000..fb6eb97 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0016_post_image_create.py @@ -0,0 +1,39 @@ +import requests +import unittest + +class TestPostCreateImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/create' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk' : '1', + 'partition' : '1', + 'code' : '1', + 'id' : '1', + 'name' : 'test', + 'repository' : '192.168.2.4' } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0017_post_image_restore.py b/native/Sources/Services/ogAdmServer/tests/units/test_0017_post_image_restore.py new file mode 100644 index 0000000..1bdeacb --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0017_post_image_restore.py @@ -0,0 +1,40 @@ +import requests +import unittest + +class TestPostRestoreImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/restore' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk' : '1', + 'partition' : '1', + 'name' : 'test', + 'repository' : '192.168.56.10', + 'type' : 'UNICAST', + 'profile': '1', + 'id': '1' } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0018_post_setup.py b/native/Sources/Services/ogAdmServer/tests/units/test_0018_post_setup.py new file mode 100644 index 0000000..16fc1d4 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0018_post_setup.py @@ -0,0 +1,56 @@ +import requests +import unittest + +class TestPostSetupMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/setup' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk' : '1', + 'cache' : '1', + 'cache_size' : '0', + 'partition_setup': [{'partition': '1', + 'code': 'LINUX', + 'filesystem': 'EMPTY', + 'size': '498688', + 'format': '0'}, + {'partition': '2', + 'code': 'LINUX-SWAP', + 'filesystem': 'EMPTY', + 'size': '199987', + 'format': '0'}, + {'partition': '3', + 'code': 'LINUX', + 'filesystem': 'EMPTY', + 'size': '31053824', + 'format': '0'}, + {'partition': '4', + 'code': 'EMPTY', + 'filesystem': 'EMPTY', + 'size': '0', + 'format': '0'}] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0019_post_image_create_basic.py b/native/Sources/Services/ogAdmServer/tests/units/test_0019_post_image_create_basic.py new file mode 100644 index 0000000..9d05b99 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0019_post_image_create_basic.py @@ -0,0 +1,47 @@ +import requests +import unittest + +class TestPostCreateBasicImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/create/basic' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk': '1', + 'partition': '1', + 'code': '131', + 'id': '8', + 'name': 'debianbasica', + 'repository': '192.168.56.10', + 'sync_params':{'sync': '1', + 'diff': '0', + 'remove': '1', + 'compress': '0', + 'cleanup': '0', + 'cache': '0', + 'cleanup_cache': '0', + 'remove_dst': '0'} } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0020_post_image_create_incremental.py b/native/Sources/Services/ogAdmServer/tests/units/test_0020_post_image_create_incremental.py new file mode 100644 index 0000000..c677e27 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0020_post_image_create_incremental.py @@ -0,0 +1,49 @@ +import requests +import unittest + +class TestPostCreateIncrementalImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/create/incremental' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk': '1', + 'partition': '1', + 'id': '3', + 'name': 'basica1', + 'repository': '192.168.56.10', + 'sync_params':{'sync': '1', + 'path': '', + 'diff': '0', + 'diff_id': '4', + 'diff_name': 'p2', + 'remove': '1', + 'compress': '0', + 'cleanup': '0', + 'cache': '0', + 'cleanup_cache': '0', + 'remove_dst': '0'} } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0021_post_image_restore_basic.py b/native/Sources/Services/ogAdmServer/tests/units/test_0021_post_image_restore_basic.py new file mode 100644 index 0000000..efe8a61 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0021_post_image_restore_basic.py @@ -0,0 +1,50 @@ +import requests +import unittest + +class TestPostRestoreBasicImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/restore/basic' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk': '1', + 'partition': '1', + 'id': '9', + 'name': 'test', + 'repository': '192.168.56.10', + 'profile': '17', + 'type': 'UNICAST', + 'sync_params':{'path': '', + 'method': '1', + 'sync': '1', + 'diff': '0', + 'remove': '1', + 'compress': '0', + 'cleanup': '0', + 'cache': '0', + 'cleanup_cache': '0', + 'remove_dst': '0'} } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0022_post_image_restore_incremental.py b/native/Sources/Services/ogAdmServer/tests/units/test_0022_post_image_restore_incremental.py new file mode 100644 index 0000000..ad7727f --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0022_post_image_restore_incremental.py @@ -0,0 +1,52 @@ +import requests +import unittest + +class TestPostRestoreIncrementalImageMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/image/restore/incremental' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ], + 'disk': '1', + 'partition': '1', + 'id': '9', + 'name': 'test', + 'repository': '192.168.56.10', + 'profile': '17', + 'type': 'UNICAST', + 'sync_params':{'diff_id': '1', + 'diff_name': 'test', + 'path': '', + 'method': '1', + 'sync': '1', + 'diff': '0', + 'remove': '1', + 'compress': '0', + 'cleanup': '0', + 'cache': '0', + 'cleanup_cache': '0', + 'remove_dst': '0'} } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + for parameter in self.json: + malformed_payload = self.json.copy() + malformed_payload.pop(parameter) + returned = requests.post(self.url, + headers=self.headers, + json=malformed_payload) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/units/test_0023_post_run_schedule.py b/native/Sources/Services/ogAdmServer/tests/units/test_0023_post_run_schedule.py new file mode 100644 index 0000000..3b92304 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/units/test_0023_post_run_schedule.py @@ -0,0 +1,28 @@ +import requests +import unittest + +class TestPostRunScheduleMethods(unittest.TestCase): + + def setUp(self): + self.url = 'http://localhost:8888/run/schedule' + self.headers = {'Authorization' : '07b3bfe728954619b58f0107ad73acc1'} + self.json = { 'clients' : [ '192.168.2.1', '192.168.2.2' ] } + + def test_post(self): + returned = requests.post(self.url, headers=self.headers, json=self.json) + self.assertEqual(returned.status_code, 200) + + def test_no_payload(self): + returned = requests.post(self.url, headers=self.headers, json=None) + self.assertEqual(returned.status_code, 400) + + def test_malformed_payload(self): + returned = requests.post(self.url, headers=self.headers, json={}) + self.assertEqual(returned.status_code, 400) + + def test_get(self): + returned = requests.get(self.url, headers=self.headers) + self.assertEqual(returned.status_code, 405) + +if __name__ == '__main__': + unittest.main() diff --git a/native/Sources/Services/ogAdmServer/tests/wol.json b/native/Sources/Services/ogAdmServer/tests/wol.json new file mode 100644 index 0000000..2a2f799 --- /dev/null +++ b/native/Sources/Services/ogAdmServer/tests/wol.json @@ -0,0 +1 @@ +{ "type" : "unicast", "clients" : [ { "addr" : "192.168.2.1", "mac" : "00AABBCCDD01" } ] } diff --git a/native/Sources/Services/ogAdmServerAux b/native/Sources/Services/ogAdmServerAux new file mode 100755 index 0000000..4add825 --- /dev/null +++ b/native/Sources/Services/ogAdmServerAux @@ -0,0 +1,47 @@ +#!/bin/bash +# Script para solicitar acciones al servidor de administración desde los clientes. +# Acciones permitidas: configurar modo de arranque. +PARM=`cat` + + + +BASEDIR=/opt/opengnsys +PATH=$PATH:$BASEDIR/bin +SERVERNAME=ogAdmServer +SERVERLOG=$BASEDIR/log/$SERVERNAME.log + + +# Añade registro de incidencias. +function echolog () { + logger --tag $0 --priority local0.info "$*" + echo "$*" +} + + +PARM1=$(echo $PARM | cut -f1 -d" ") +PARM2=$(echo $PARM | cut -f2 -d" ") +PARM3=$(echo $PARM | cut -f3 -d" ") +PARM4=$(echo $PARM | cut -f4 -d" ") + + +case "$PARM1" in + SET_CLIENTMODE) + #1 SET_CLIENTMODE + #2 template + #3 pc_name o group_pc +#4 modo temporal o permanente + + TEMPLATE="$PARM2" + PC="$PARM3" +#incluyo parametro de MODO + MODO="$PARM4" + echolog "Ejecutar $(which setclientmode) $FILE $MCASTOPT" +#incluyo parametro de MODO + setclientmode $TEMPLATE $PC $MODO &>> $SERVERLOG + exit $? + ;; + default) + echolog "Solicitud con parametros \"$PARM\" no realizada, no registrada o con errores" + ;; +esac + diff --git a/native/Sources/Services/opengnsys.default b/native/Sources/Services/opengnsys.default new file mode 100644 index 0000000..d7376cf --- /dev/null +++ b/native/Sources/Services/opengnsys.default @@ -0,0 +1,15 @@ +# RUN_OGADMSERVER defined as OpenGnsys Admin Server +# RUN_OGADMREPO defined as OpenGnsys Repository Manager +# RUN_OGADMAGENT run task scheduler service, only if Admin Server is enabled +# RUN_BTTRACKER run Bittorrent Tracker, only if Repository is enabled +# RUN_BTSEEDER start seeding of selected torrent files, only if Repository is enabled +# BTSEEDER_PRIORITY nice priority to seed torrent files; recommended values: +# 8 for Admin Server or Repo without Torrent +# 0 for Admin Server and Repo with Torrent +# -8 for Repo with Torrent +RUN_OGADMSERVER="yes" +RUN_OGADMREPO="yes" +RUN_OGADMAGENT="yes" +RUN_BTTRACKER="yes" +RUN_BTSEEDER="yes" +BTSEEDER_PRIORITY=0 diff --git a/native/Sources/Services/opengnsys.init b/native/Sources/Services/opengnsys.init new file mode 100755 index 0000000..ae27593 --- /dev/null +++ b/native/Sources/Services/opengnsys.init @@ -0,0 +1,224 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: opengnsys +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +# Short-Description: Servicios del sistema OpenGnsys +# Description: Servicios del sistema OpenGnsys +### END INIT INFO + +# +# Definiciones globales +# +BASEDIR=/opt/opengnsys +OPENGNSYSUSER="opengnsys" +IMAGEDIR=$BASEDIR/images +CLIENTLOGDIR=$BASEDIR/log/clients + +# +# Servidor de OpenGnsys +# +SERVERNAME=ogAdmServer +SERVERDAEMON=$BASEDIR/sbin/$SERVERNAME +SERVERCFG=$BASEDIR/etc/$SERVERNAME.cfg +SERVERLOG=$BASEDIR/log/$SERVERNAME.log +SERVERDAEMON_OPTIONS="-f $SERVERCFG -l $SERVERLOG" + +# +# Servidor de Repositorio +# +############## ADV +REPOAUXNAME=ogAdmRepoAux +REPOAUXDAEMON=$BASEDIR/sbin/$REPOAUXNAME +REPOAUXPORT=$(awk -F= '/PUERTO/ {print $2+1}' $SERVERCFG 2>/dev/null) +############## ADV +############# IRINA # para setBootMode desde el cliente +SERVERAUXNAME=ogAdmServerAux +SERVERAUXDAEMON=$BASEDIR/sbin/$SERVERAUXNAME +SERVERAUXPORT=2011 +############# IRINA + +# +# Servidor de tareas programadas +# +AGENTNAME=ogAdmAgent +AGENTDAEMON=$BASEDIR/sbin/$AGENTNAME +AGENTCFG=$BASEDIR/etc/$AGENTNAME.cfg +AGENTLOG=$BASEDIR/log/$AGENTNAME.log +AGENTDAEMON_OPTIONS="-f $AGENTCFG -l $AGENTLOG" + +# +# Opciones Bittorrent +# + +BTTRACK=/usr/bin/bttrack.bittorrent +BTSEEDER=/usr/bin/btlaunchmany.bittornado +BTTRACKPORT=6969 +BTTRACKDFILE=/tmp/dstate +BTTRACKLOG=$BASEDIR/log/bttrack.log +BTINTERVAL=30 +BTTORRENTSDIR=$BASEDIR/images +BTTRACK_OPTIONS=" --port $BTTRACKPORT --dfile $BTTRACKDFILE --reannounce_interval $BTINTERVAL --logfile $BTTRACKLOG --allowed_dir $BTTORRENTSDIR --allow_get 1" +BTTRACKPID="/var/run/bttrack.pid" +BTSEEDERPID="/var/run/btseeder.pid" + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin:/usr/bin" + +# Read config file if it is present. +if [ -r /etc/default/opengnsys ]; then + source /etc/default/opengnsys +fi + +# Configuración de arranque según la distribución Linux usada. +config() { + if [ -f /etc/os-release ]; then + source /etc/os-release + OSDISTRIB="$ID" + else + OSDISTRIB=$(lsb_release -is 2>/dev/null) + fi + OSDISTRIB="${OSDISTRIB,,}" + case "$OSDISTRIB" in + ubuntu|debian|linuxmint) + INITFUNCTIONS=/lib/lsb/init-functions + DAEMONSTART="start-stop-daemon --start --quiet --background --exec" + EXTRAOPTS="--" + DAEMONSTOP="start-stop-daemon --stop --quiet --oknodo --name" + ACTIONMSG="log_daemon_msg" + SUCCESSMSG="log_end_msg 0" + FAILMSG="log_end_msg 1" + TRACKERSTART="start-stop-daemon --make-pidfile --pidfile $BTTRACKPID --start --quiet --background --exec" + BTTRACK_OPTIONS="$BTTRACK_OPTIONS --parse_allowed_interval 1" + TRACKERSTOP="start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $BTTRACKPID" + SEEDERSTART="start-stop-daemon --make-pidfile --pidfile $BTSEEDERPID --start --quiet --background --exec" + SEEDERSTOP="start-stop-daemon --stop --quiet --oknodo --pidfile $BTSEEDERPID" + ;; + centos|fedora) + INITFUNCTIONS=/etc/init.d/functions + DAEMONSTART="daemon" + ENDOPTS="&" + DAEMONSTOP="killproc" + ACTIONMSG="echo -n" + SUCCESSMSG="eval ( success; echo )" + FAILMSG="eval ( failure; echo )" + BTTRACK=/usr/bin/bttrack.py + BTSEEDER=/usr/bin/btlaunchmany.py + TRACKERSTART="daemon --pidfile $BTTRACKPID" + TRACKERSTOP="killproc -p $BTTRACKPID $BTTRACK" + SEEDERSTART="daemon --pidfile $BTSEEDERPID" + SEEDERSTOP="killproc -p $BTSEEDERPID $BTSEEDER" + ;; + *) echo "Distribución Linux desconcocida o no soportada." + exit ;; + esac + if [ -r $INITFUNCTIONS ]; then + source $INITFUNCTIONS + fi +} + +arranca_demonios() { + # Comprobar que está instalado OpenGnsys. + if [ ! -d $BASEDIR ]; then + $ACTIONMSG "ERROR: No existe el directorio $BASEDIR" + $FAILMSG + exit $? + fi + # Deshabilitar modo reforzado de SELinux. + [ -f /selinux/enforce ] && echo 0 > /selinux/enforce + # Verificar permisos básicos. + if [ "$(stat --printf="%A%G" $IMAGEDIR 2>/dev/null)" != "drwxrwxr-x$OPENGNSYSUSER" ]; then + mkdir $IMAGEDIR 2>/dev/null + chmod 775 $IMAGEDIR + chgrp $OPENGNSYSUSER $IMAGEDIR + fi + if [ "$(stat --printf="%A%G" $CLIENTLOGDIR 2>/dev/null)" != "drwxrwxr-x$OPENGNSYSUSER" ]; then + mkdir -p $CLIENTLOGDIR 2>/dev/null + chmod 775 $CLIENTLOGDIR + chgrp $OPENGNSYSUSER $CLIENTLOGDIR + fi + # Arrancar los servicios indicados. + if [ $RUN_OGADMSERVER = "yes" ]; then + $ACTIONMSG "Iniciando demonio: $SERVERNAME" + $DAEMONSTART $SERVERDAEMON $EXTRAOPTS $SERVERDAEMON_OPTIONS $ENDOPTS + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + # Para SetBootmode desde el cliente + $ACTIONMSG "Iniciando demonio: $SERVERAUXNAME" # + faucet $SERVERAUXPORT --daemon --in bash -c "$SERVERAUXDAEMON" # NUEVO + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + fi + if [ $RUN_OGADMREPO = "yes" ]; then + $ACTIONMSG "Iniciando demonio: $REPOAUXNAME" + faucet $REPOAUXPORT --daemon --in bash -c "$REPOAUXDAEMON" + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + fi + if [ $RUN_OGADMSERVER = "yes" ] && [ $RUN_OGADMAGENT = "yes" ]; then + sleep 5 # Damos tiempo a que ogAdmServer este funcionando + fi + if [ $RUN_OGADMAGENT = "yes" ]; then + $ACTIONMSG "Iniciando demonio: $AGENTNAME" + $DAEMONSTART $AGENTDAEMON $EXTRAOPTS $AGENTDAEMON_OPTIONS $ENDOPTS + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + fi + if [ $RUN_BTTRACKER = "yes" ]; then + $ACTIONMSG "Iniciando demonio: $BTTRACK" + $TRACKERSTART $BTTRACK $EXTRAOPTS $BTTRACK_OPTIONS $ENDOPTS + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + fi + if [ $RUN_BTSEEDER = "yes" ]; then + $ACTIONMSG "Iniciando demonio: $BTSEEDER" + $SEEDERSTART $BTSEEDER $EXTRAOPTS $BTTORRENTSDIR &>/dev/null $ENDOPTS + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + fi + +} + +para_demonios() { + if [ -e $BTSEEDERPID ]; then + $ACTIONMSG "Parando demonio: $BTSEEDER" + $SEEDERSTOP + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + rm -f $BTSEEDERPID + fi + if [ -e $BTTRACKPID ]; then + $ACTIONMSG "Parando demonio: $BTTRACK" + $TRACKERSTOP + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + rm -f $BTTRACKPID + fi + $ACTIONMSG "Parando demonio: $AGENTNAME" + $DAEMONSTOP $AGENTNAME + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG + $ACTIONMSG "Parando demonio: $REPOAUXNAME" + pkill faucet + [ $? -le 1 ] && $SUCCESSMSG || $FAILMSG + $ACTIONMSG "Parando demonio: $SERVERNAME" + $DAEMONSTOP $SERVERNAME + [ $? = 0 ] && $SUCCESSMSG || $FAILMSG +} + +config + +case "$1" in + start) + arranca_demonios + ;; + stop) + para_demonios + ;; + restart) + para_demonios + arranca_demonios + ;; + + *) + echo "Uso: $0 {start|stop|restart}" + exit 1 + ;; +esac + +exit 0 +