Programacin de Sistemas.	
	
	TEMA II. 
	Modelo UNIX.

Objetivo: Entender la filosofia de programacin de sistemas a partir
del Modelo UNIX.

+ UNIX es un sistema operativo multiusuario, multitarea, multithreading.

+ UNIX consiste en :
	Kernel --- Se encarga de administrar recursos de cmputo tales
	como CPU, RAM, Disco,Equipos Perifricos y servicios de Red.

	Shell --- Se encarga de efectuar la interaccin entre el usuario
	y el kernel del sistema operativo. Ejecuta los programas del usuario.
	Existen varios tipos de Shell: Bourne Shell, C Shell y Korn Shell. Pero
	UNIX permite que el usuario defina su propio Shell y lo incorpore dentro
	del sistema operativo. Dicho shell tiene un conjunto de instrucciones
	para crear tareas del sistema operativo, que permite combinar varios
	comandos o programas de usuario y sistema operativo.

+ Versiones y Estndares

Actualmente existen diversas versiones de UNIX, y todas ellas atadas a la
plataforma donde se ejecuta.
Sin embargo, en la historia de UNIX dos han sido las corrientes, originadas
por la forma de administrar, formato de comandos, definicin de llamadas al
 sistema y libreries,  construccin del kernel y adminstracin de perifricos.

	Berkeley Software Distribution (BSD)  - BSDI, Linux, Ultrix
	UNIX System V Release 4. Solaris, OSF/1, HPUX, AIX, IRIX.

Actualmente la versin soportada por la industria es System V, sin embargo,
con el auge de Linux, BSD y System V se han combinado y puesto lo mejor de
ambas filosofias.

Se han diseado otros estndares con el objetivo de construir programas 
portables entre sistemas UNIX y an no UNIX (por ejemplo NT). Uno de esos
estndares es POSIX (Portable Operating System Interface) que es un conjunto
de definiciones para que un programador las siga y cumpla la portabilidad.

ANSI C es otro estndar que se utiliza para que las aplicaciones sean portables.

En este curso se usar ANSI C, POSIX y System V, para permitir que se puedan
utilizar en plataforma como OSF/1, Solaris y Linux, entro otras.

+ Llamadas al sistema y librerias de funciones.

Una llamada al sistema son los puntos directos de entrada para que un programa
 pueda obtener servicios del kernel.

Las librerias de funciones son un conjunto de rutinas para implantar las 
funciones requeridas por ANSI C. Las llamadas al sistema son utilizadas por
las librerias de funciones. Las librerias de funciones tienen como objetivo
ocultar al usuario algunos aspectos de manejo de recursos de cmputo.

Por ejemplo, para poder indicar al kernel que se necesita memoria, se debe
utilizar la llamada al sistema brk(), en cambio, la funcin malloc() es una
rutina que asigna memoria y para su funcionamiento utiliza la llamada brk().

Para un programador es indistinto si usa una llamada al sistema o una funcin,
dado que el invoca ambas de la misma forma desde un lenguaje de programacin.

Se recomienda utilizar llamadas al sistema cuando se necesite utilizar un
recurso del sistema operativo de una forma especfica.

UNIX contiene un conjunto de manuales, divididos en secciones:
	 La seccion 2 est dedicada a llamadas al sistema.
	 La seccion 3 est dedicada a la libreria de funciones C.

Ejercicio:
+ Determinar si las siguientes rutinas son llamadas al sistema o funciones:
(Tip, teclear man nombre-rutina, y la pgina indicara 
nombre-rutina(numero seccin) )
fopen, open, dup, printf, brk, malloc, socket, ioctl.

+ En el libro el Lenguaje de Programacin C de Kernighan, uno de los
apndices describe las rutinas de ANSI C. Explicar cada clasificacin y
dar dos ejemplos de funciones.

+ Dar el comando 

man -s 2 intro

para ver todas las llamadas al sistema. 

+ API.

La manera de saber como incorporar una llamada al sistema o una funcin es
utilizando las definiciones proporcionadas por la interfaz de programacin de
aplicaciones o API del sistema. 

Un API indica la definicin de estructuras de datos y rutinas para utilizar
cierto servicio del sistema operativo.

Normalmente, dichas definiciones son presentadas en un archivo de encabezado
de lenguaje C; los cuales se deben incorporar dentro del programa.

En los sistemas UNIX, dichos encabezados se encuentran bajo el directorio
/usr/include.

+ Uso del API y compilacin en el ambiente UNIX.

Para incorporar una llamada al sistema y/o funcin de ANSI C, se deben
seguir los siguientes pasos:

1) Determinar que llamada o funcion se va a utilizar.
2) Checar en el manual del sistema acerca de la llamada o funcion e incluir
los archivos de encabezado indicados en el manual. Determinar el formato
de la rutina.
3) Codificar la lgica del programa.
4) Compilar el programa con el compilador cc o gcc.
5) Generar el programa ejecutable.

Ejemplo:

Para leer caracter por caracter de la entrada estandar se debe utilizar una
llamada al sistema denominada read. Escribir un programa que lea un caracter
y lo imprima a salida estndar utilizando la llamada al sistema write.

Pasos
1)  Determinar que llamada o funcion se va a utilizar.
	Se debe utilizar la llamada read() y write().
2) Checar en el manual del sistema acerca de la llamada o funcion e incluir
los archivos de encabezado indicados en el manual.

man -s 2 read 
Despliega esto:

#include <unistd.h>
Su formato es:
ssize_t read(int fildes,void *buf, size_t nbyte)

para UNIX el tipo de dato size_t y ssize_t es un numero long.

Esta funcin se lee como una funcin que recibe tres argumentos, el primero
un entero que es un descriptor de archivos, el segundo un apuntador al buffer
que va a almacenar la informacin y el tercero, el tamao del buffer. Retorna
el nmero de bytes leidos.



man -s 2 write

#include <unistd.h>

ssize_t write(int fildes,void *buf, size_t nbyte)

Esta funcin se lee como una funcin que recibe tres argumentos, el primero
un entero que es un descriptor de archivos, el segundo un apuntador al buffer
que almacenar la inforamacin a escribir y el tercero, el tamao del buffer a
escribir. Retorna el nmero de bytes leidos.


Por tanto, se debe incluir el archivo de encabezado #include <unistd.h>


 
3) Codificar la lgica del programa.
Este programa debe leer la entrada estndar hasta que encuentre un fin
de archivo (). Y escribir lo que lee a la salida estndar. 

/**** Ejemplo 1 Tema II
 *	Programa que lee caracteres de la entrada estndar (teclado)
 *   	y lo escribe a la salida estndar (pantalla)
****/
/*Se incluye la definicin de las llamadas read y write*/
#include <unistd.h>

/*Programa principal*/

main() {
	/*Variable donde se almacena los caracteres, se inicializa a 0*/
	char ch=-1;

	while (ch!='\0') {
		/* El descriptor de archivo 0 es la entrada estndar,
		 * se indica la direccion del buffer y su tamanio
		 */
		read(0,&ch,sizeof(char));
		/* El descriptor de archivo 1 es la salida estandar,
		 * se indica la direccion del buffer y su tamanio
		 */

		write(1,&ch,sizeof(char));

	}

}
4) Compilar el programa con el compilador cc o gcc.

gcc -c Ejemplo1.c

esta compilacin debe generar un archivo denominado Ejemplo1.o, que es
el programa en cdigo mquina o archivo objeto.

La bandera -c indica al compilador que compile el programa.

5) Generar el programa ejecutable.

gcc -o Ejemplo1 Ejemplo1.o

Esta instruccin indica que se debe generar un ejecutable con el nombre
Ejemplo1, la opcin -o sirve para indicar dicho nombre, si se suprime esta
opcion, genera un archivo denominado a.out. Se debe dar la lista de todos
los programas objetos relacionados con el ejecutable.

Para ejecutar este programa, teclear

Ejemplo1

y dar cualquier texto y salto de carro. El programa concluye al recibir
un fin de archivo ().

+ Descriptores de archivos.

En UNIX cualquier archivo, directorio o dispositivo perifrico es tratado
como un archivo.

En UNIX, para poder manipular un archivo, cada usuario debe indicar que
nmero de descriptor de archivo va a manipular.

En UNIX los tres primeros descriptores de archivos son utilizados para
designar lo que se conoce como la entrada estndar, salida estndar y 
error estndar.

	Descriptor de Archivo	Archivo			Comentario
	0			Entrada Estndar	Teclado, si no
							se utiliza redireccion
	1			Salida Estndar		Terminal, si no
							se utiliza redireccion	
	2			Error Estndar		Terminal, si no
							se utiliza redireccion,
							aqui se deben imprimir
							mensajes de error

El redireccionamiento consiste en reemplazar la entrada estndar o salida
estndar por otro archivo.

Por ejemplo, si no se quiere tomar lectura del teclado, sino de un archivo,
se debe utilizar el operador de direccionamiento de entrada <.
	
Para probar este concepto, utilizar el Ejemplo1

Ejemplo1 < Ejemplo1.c

Esto lo que hace es desplegar el contendio del archivo Ejemplo1.c (como
el comando type de DOS o cat de UNIX).

Para direccionar la salida, se utiliza el operador >.


Ejemplo1 < Ejemplo1.c > salida

es el equivalente a realizar un copy o cp, del archivo Ejemplo1.c a salida.


+ Archivo de compilacin. Makefile

Con el fin de automatizar las tareas de compilacion y evitar que el programador
este proporcionando de una forma repetitiva dos o mas instrucciones, UNIX
ofrece una herramienta denominada make.

Esta herramienta lee un archivo denominado Makefile, que contiene las 
instrucciones de compilacion y generacin de un programa ejecutable.

Un archivo Makefile se compone de las reglas de compilacin de un programa.

Por ejemplo, el archivo Makefile del programa anterior:

#Makefile para los ejemplos del captulo 2.

Ejemplo1: Ejemplo1.o
	gcc -o Ejemplo1 Ejemplo1.o

Ejemplo1.o: Ejemplo1.c
	gcc -c Ejemplo1.c

clean:
	rm *.o
        rm Ejemplo1


La primera regla se puede leer asi:

Su nombre es Ejemplo1 y se sigue de dos puntos (sin espacio) y se
indican las dependencias con otras reglar para poder ejecutar la instruccin.
En este caso, para generar el ejecutable Ejemplo1, se debe tener creado el
archivo  Ejemplo1.o. Si este archivo existe, manda a ejecutar el compilador
para generar el ejecutable. La linea que tiene la sentencia de compilacin
debe tener un tabulador como primer caracter, de lo contrario, falla la
ejecucin.

Ejemplo1: Ejemplo1.o
	gcc -o Ejemplo1 Ejemplo1.o

Si el archivo Ejemplo1.o no existe, entonces, busca una regla para generarlo,
en esta caso es:

Ejemplo1.o: Ejemplo1.c
	gcc -c Ejemplo1.c

En este caso, esta regla indica que Ejemplo1.o depende de la existencia del
programa Ejemplo1.c (generado por el programador), y para generar el archivo
Ejemplo1.o debe ejecutar el comando gcc con opcin -c sobre el cdigo fuente.

La regla clean sirve para indicar las instrucciones necesarias para borrar
los programas ejecutables y objeto.

Para usar este archivo Makefile, se debe teclear desde la linea de comandos:

make Ejemplo1
gcc -c Ejemplo1.c
gcc -o Ejemplo1 Ejemplo1.o

este genera el archivo ejecutable.

Para limpiar.
make clean
rm *.o
rm Ejemplo1

Ejercicio. 

+ Construir un programa que lea caracteres de la entrada estndar y lleve
el conteo de caracteres leidos. Al finalizar la lectura del entrada estndar,
imprimir el nmero de caracteres leidos.
Usar la llamada al sistema read para leer los caracteres. Imprimir el
resultado con un printf.

Modificar el archivo Makefile e incluir las instrucciones para generar
el programa objeto y ejecutable.

+ En que formato deja los programas ejecutables ? 
(checar el comando file de UNIX)

+ Investigar en los manuales del sistema, o en Internet o en
el libro de UNIX Programacin prctica, apendice A,
 mas sobre el comando make y la
sintxis del archivo Makefile. Es necesario que entiendas que un Makefile
contiene instrucciones en un lenguaje especial para compilar, generar
 ejecutables y mantener cdigo fuente.


+ Lista de argumentos y variables del entorno.

La filosofa de UNIX es que sus comandos reciban parmetros o argumentos para
que dichos comandos varien su comportamiento segn las necesidades del usuario.

Para esto, el sistema operativo permite al programador obtener dichos argumentos
y manipularlos dentro del programa.

Para esto utiliza dos variables, que son pasadas como argumentos de la rutina
main() del programa.

El primer argumento, que es de tipo entero, y que normalmente es denominada
argc (pero no es forzoso llamarla as), indica el nmero de argumentos que
se reciben en la linea de comandos.

El segundo argumento es un arreglo de apuntadores a cadenas de caracteres
( char * argv[]).

El siguiente ejemplo ilustra este concepto:

/**** Ejemplo 3 Tema II
 *	Programa que lee los argumentos de la linea de comandos
 *   	y los imprime a la salida estndar (pantalla)
****/
#include <stdio.h>

main(int argc, char * argv[]) {

	int i;

	for (i=0;i<argc;i++)
		printf("%s ",argv[i]);

	printf("\n");

}

Al ejecutar este programa sin argumentos

Ejemplo3
	imprime
Ejemplo3

dado que la variable argc tiene valor 1. El sistema operativo pone en
la primera celda del arreglo el nombre del programa (es decir, nunca se debe
tener un argc igual a 0).

Si se teclea

Ejemplo3 hola mundo

la salida es:

Ejemplo3  hola  mundo

El valor de argc es 3.
En la celda 1 y 2 estn las cadenas de caractes hola y mundo respectivamente.


Adems, todos los programas tienen acceso a las variables de entorno. Dichas
variables son definidas por el shell del usuario y contienen ciertos valores,
por ejemplo, el directorio de trabajo o HOME, la ruta de programas ejecutables
o PATH.

El programador puede manipular estas variables, declarando en la rutina main
tres argumentos, los dos primeros relacionados con la lista de argumentos
y el tercero es un arreglo de apuntadores a cadena de caracteres. Normalmente
se define con el nombre envp y de tipo char * envp[]. En la ltima celda
del arreglo envp se pone un apuntador nulo, para indicar que no existen
mas variables de ambiente.


El siguiente ejemplo ilustra el uso de las variables de entorno.

/**** Ejemplo 4 Tema II
 *	Programa que lee lasvariables de entorno
 *   	y las imprime a la salida estndar (pantalla)
****/
#include <stdio.h>

main(int argc, char * argv[], char * envp[]) {

	int i;

	for (i=0;envp[i]!= (char *) 0;i++)
		printf("%s\n",envp[i]);


}

Al ejecutar este programa

Ejemplo4

aparece

CLASSPATH=/opt/corba:/opt/weblogic/classes:/opt/weblogic/lib/weblogicaux.jar:.
DISPLAY=:0.0
HELPPATH=/usr/openwin/lib/locale:/usr/openwin/lib/help
HOME=/opt/gus
HZ=100
JACORB=/opt/corba
LANG=C
LD_LIBRARY_PATH=/opt/weblogic/lib/solaris
LOGNAME=gus
MAIL=/var/mail/gus
MANPATH=/usr/openwin/share/man:/usr/man
NOSUNVIEW=0
OPENWINHOME=/usr/openwin
PATH=/opt/corba/bin:/bin:/opt/FSFgcc/bin:/usr/ccs/bin:/usr/ccs/lib:/usr/openwin/bin:/etc:.
PWD=/opt/gus/cibernetica/src/tema2
SHELL=/bin/csh
TERM=sun-cmd
TZ=Mexico/General
USER=gus
WEBLOGIC=/opt/weblogic
XFILESEARCHPATH=/usr/openwin/lib/locale/%L/%T/%N%S:/usr/openwin/lib/%T/%N%S
XINITRC=/usr/openwin/lib/Xinitrc
WINDOW_TERMIOS=
TERMCAP=sun-cmd:te=\E[>4h:ti=\E[>4l:tc=sun:

esta salida puede varia segun la configuracin del shell donde se ejecute.

Compare esta salida contra el comando setenv (para CSH) o set (para SH o KSH)

Ejercicios.

+ El Ejemplo5 debe utilizar tanto linea de comandos y variables de entorno.
Para esto, el Ejemplo5 debe extender al Ejemplo4, pero al recibir un argumento
en la linea de comandos, debe insertar en el arreglo de varibles de ambiente
la nueva variable.
Por ejemplo

Ejemplo5 

sin ningun argumento, debe comportarse como el Ejemplo4.

Pero 

Ejemplo5 GUSENV=gus

debe insertar una nueva variable de ambiente. Imprimir de nuevo todo el
arreglo de variables de ambiente

 
 
+ Mantenimiento de versiones de control de cdigo.

Algunas veces es necesario guardar diferentes versiones del cdigo fuente
de un programa. Por ejemplo, la versin 1 de un programa que ya est funcionando
va a ser modificada para darle nuevas funciones. Normalmente al realizar
nuevas modificaciones, se empieza a alterar el comportamiento del programa
versin 1 y lleva a casos en los cuales se puede perder la funcionalidad
adquirida.

 Con el fin de que el programador pueda recuperar la versin anterior,
se puede crear un respaldo de su primer programa. Esto lleva a que se tengan
mltiples copias de cdigo fuente.

UNIX provee una herramienta que permite crear versiones de cgido, denominada
SCCS (Source Code Control System).

El siguiente ejemplo ilustra su uso.

/*Ejemplo6*/

main() {

	/*imprime una campana*/
	printf("%c",7);
}

esta versin lo unico que hace es un "beep".

Pero si queremos un programa el cual reciba como parmetro el nmero de 
"beeps" a realizar, se debe incorporar un ciclo. Por omisin, sin ningn
argumento en la linea de comandos, slo imprime un beep (comportamiento
original).

Para esto, antes de modificar el programa, dar este comando.

prompt% sccs create Ejemplo6.c

Ejemplo6.c
No id keywords (cm7)
1.1
9 lines
No id keywods (cm7)

Esto crea un directorio SCCS y cambia los permisos de los archivos a
solo lectura. Es muy importante NO CAMBIARLOS manualmente. Antes de editar
el archivo se debe utilizar el comando sccs de aqu en adelante.

Para editar una nueva version.

sccs edit Ejemplo6.c
1.1
new delta 1.2
9 lines

Y al pedir informacin 

sccs info
Ejemplo6.c: being edited: 1.1 1.2 gus 99/02/06 14:48:50

se puede notar que indica la versin que se est editando, que usuario y
fechas.

Con el editor de texto, modificar el programa




/*Ejemplo6*/

main(int argc, char * argv[]) {
	 	
	if (argc == 1) {
		/*imprime una campana*/
		printf("%c",7);
	} else {
		int contador= atoi(argv[1]);
		int i;
	 	for (i=1;i<=contador;i++)
			printf("%c",7);
	}
}

cuando se pruebe esta  nueva funcin, se puede crear una nueva version.

sccs delta Ejemplo6.c

comments? Indicar el numero de campanas a sonar
No id keywords (cm7)
1.2
11 inserted
3 deleted
6 unchanged

Al checar
 sccs info
Nothing being edited

Si se quiere obtener la version 1.1

sccs get -r 1.1 Ejemplo6.c

Observar que se tiene el primer programa.

Tambien se pueden comparar versiones.

sccs diffs Ejemplo6.c 


------- Ejemplo6.c -------
3c3
< main(int argc, char * argv[]) {
---
> main() {
5,14c5,6
<       if (argc == 1) {
<               /*imprime una campana*/
<               printf("%c",7);
<       } else {
<               int contador= atoi(argv[1]);
<               int i;
<               for (i=1;i<=contador;i++)
<                       printf("%c",7);
<       }
< 
---
>       /*imprime una campana*/
>       printf("%c",7);

Ejercicio.
+ Investigar mas sobre el comando sccs.



+ Usuarios y grupos en UNIX.

UNIX al ser un sistema multiusuario, debe definir el concepto de usuario.
Con este concepto, UNIX controla a los usuarios y les otorga o deniega 
recursos segn el tipo de usuario.

Adems, se pueden agrupar usuarios en grupos, con el fin de que a un conjunto
de usuarios se les puede permitir o denegar acceso a ciertos recursos.

Cuando se entra en sesin con UNIX, automticamente el kernel identifica
cada proceso como correspondiente al usuario en sesin. Gracias a esto,
un usuario no puede manipular los procesos o archivos de otros usuarios.

El nico usuario que es capaza de manipular todos los recursos es el 
superusuario o administrador, conocido como root.

Para UNIX, cada usuario y grupo tienen un identificador, que es un nmero
unico. El superusuario tiene el identificador de usuario 0. Checar los
archivos /etc/passwd y /etc/group

Para poder manipular los usuarios, existen diversas llamadas al sistema.

Dos de ellas son las llamadas getuid() y getgid(). Checar el manual 
del sistema para la descripcin de las mismas.

El siguiente ejemplo permite obtener el id del usuario y el grupo de
la sesin actual.

/* Ejemplo 7 Tema II
 * Obtener el id de usuario y grupo utilizando las llamadas al sistema
 * getuid() y getgid()
 */

#include <sys/types.h>
#include <unistd.h>
 


main() {

	printf("uid=%d gid=%d\n",getuid(),getgid());
}

Comparar este programa con el comando id de UNIX.

Las llamadas getuid y getgid son llamadas que retornan un nmero entero,
y dicho nmero est definido en el archivo /etc/passwd y /etc/group para
usuarios y grupos resepectivamente.

Estos identificadores son los que se conocen como Real User Id y Real Group Id.

Ahora probemos la seguridad de UNIX. UNIX provee dos llamadas mas, denominadas
setuid() y setgid(). Esto permite adquirir los identificadores de otro usuario.
Si UNIX no tuviera control sobre esta llamada, cualquier usuario podra tomar
el identificador del otro y violar la seguridad!!! (En antao esto era muy
comn por errores de programacin de los primeros UNIX, y hoy en dia existe
en muchos casos con sistemas distribuidos y potencialmente hay varios huecos
de seguridad en varios sistemas en Internet)

/* Ejemplo 8. Intento de hacker.
 * Ponerse el uid del usuario, esto se indica desde la linea de comando
 * El superusuario tiene un uid de 0 
 */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

main(int argc,char * argv[]) {
	int uid;

	/*No se recibe nada*/
	if (argc == 1)
		/*poner el uid del usuario actual*/
		uid= getuid();
	else {
		/*convertir a entero la linea de comandos*/
		uid= atoi(argv[1]);
	}

	if (setuid(uid)==-1){
		/*error, imprimir con funcion perror*/
		perror("Intenta otra vez");
	}

	printf("Hackeo exitoso!!");
}

Intente  correr

Ejemplo8

Hackeo exitoso!!!

Ejemplo8 0
Intenta otra vez: Not owner


Se puede notar que el primer intento fue exitoso, ya que el usuario si
se puede poner su propio identificador.

Pero el segundo no es exitoso, ya que no es posible que un usuario se ponga
el identificador del superusuario. Si en el segundo intento si se pudo
realizar, entonces se ha descubierto un nuevo hueco de seguridad en este
sistema!!!

Pero si fuera posible entrar como root

su
Password: *******

Ejemplo8 0
Hackeo exitoso!!!

Ejemplo8 100
Hackeo exitoso!!!

Y esto se debe a que root puede hacer cualquier cosa. Por eso es que los
hackers, al encontrar un sistema UNIX, lo primero que intentan es violar
el password de root.

Sin embargo, UNIX en algunos casos necesita dar de una forma temporal acceso.
Por ejemplo, el comando passwd que cambia el password de un usuario debe
escribir sobre un archivo denominado /etc/passwd (o /etc/shadow) que solo
pertenece a root. Esto implica que el superusuario es el nico capaz de
cambiar passwords. Sin embargo, para evitar esta situacin, UNIX maneja
otro nivel de usuario y grupo, el usuario y grupo Efectivo.

El concepto de usuario y grupo Efectivo permite que un programa adquiera
de forma temporal el identificador de otro usuario. Para esto, el otro
usuario le debe otorgar permisos a los demas.

El siguiente ejemplo muestra, en lenguaje C y con algunos comandos de UNIX
como es posible esto.


/* Ejemplo 9. Otorgar permisos
 * Ponerse el uid del usuario, esto se indica desde la linea de comando
 * El superusuario tiene un uid de 0 
 * Es necesario utilizar el comando chmod para poner permisos setuid.
 * Se intenta abrir un archivo de solo lectura para otro usuario
 */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

main(int argc,char * argv[]) {
	int uid;
	printf("uid=%d gid=%d\n euid=%d egid=%d\n",getuid(),getgid(),geteuid(),getegid());

	/*No se recibe nada*/
	if (argc == 1)
		/*poner el uid del usuario actual*/
		uid= geteuid();
	else {
		/*convertir a entero la linea de comandos*/
		uid= atoi(argv[1]);
	}

	if (seteuid(uid)==-1){
		/*error, imprimir con funcion perror*/
		perror("Checa que tengas el permiso setuid");
	}

	if ( fopen("./protegido.txt","r" == 0)
			perror("no puedo leer el archivo");

	
	printf("lectura exitosa");
}

Para lograr que este programa ayude a entender este concepto:

+ Compilarlo.

+ Cambiar permisos 

chmod 755 Ejemplo9


+ Crear el archivo protegido.txt en el mismo lugar donde reside Ejemplo9
cat > protegido.txt
hola


+ Cambiar a permisos
chmod 400 protegido.txt


+ Pedir al compaero de a lado que ejecute en tu directorio
Ejemplo9

uid=1001 gid=1
 euid=1001 egid=1
no puedo leer el archivo: Permission denied

+Aplicar este comando SOBRE su programa ejecutable.

chmod 4755 Ejemplo9

este comando es el que permite el uso del setuid.

+ Pedir al compaero de a lado que ejecute en tu directorio
Ejemplo9

uid=1001 gid=1
 euid=0 egid=1
lectura exitosa

Qu es lo que sucede.

Al momento de generar el programa, este queda con permisos de ejecucin
para cualquier usuario, aunque con el segundo comando se asegura este hecho.

Al crear el archivo protegido.txt, se pone solo de lectura para el propietario.

Si otro usuario trata de tener acceso, UNIX no le otorga permisos.

Pero si el usuario otorga el permiso 4755, que consiste en "prestar" su id
a cualquier usuario o lo conoce como el permiso de setuid, es factible realizar
la lectura del archivo protegido.

Observese que el euid cambia cuando se aplica el permiso. En esta caso
se utiliz root como el usuario propietario de Ejemplo9 y protegido.txt. 

Un id efectivo solo se puede aplicar sobre programas ejecutables.

Un intruso del sistema lo primero que trata de hacer es buscar acceso
a la cuenta de administrador. Algunos instantes le bastan para crear
comandos parecidos al aqu expuesto y despues ganar acceso completo al
sistema.

Ejemplo:

+ En base a lo expuesto,explicar como esta hecho el comando su y passwd de
UNIX.
+ Investigar en Internet sobre huecos de seguridad relacionados con el
permiso setuid y:
	NFS
	HTTP
	FTP
	Correo electrnico o sendmail.

+ Permisos de archivos y directorios.

En el punto pasado se utilizaron permisos sobre archivos. 

Los permisos de archivos y directorios son
	lectura (r) para lectura de un archivo o directorio
	escritura (w) para escritura de un archivo o directorio
	ejecucin (x) para ejecucin de un archio o en el caso de un
			directorio, poder cambiarse a dicho directorio.

Adems UNIX entiende, para cada archivo, que existen tres tipos de entidades
que pueden manipularlo.

	usuario - el dueo del archivo
	grupo	- el conjunto de usuarios 
	otros	- ni el usuario ni el grupo

Y cada entidad puede tener los distintos permisos de archivos. Es decir el
dueo puede leer,escribir y ejecutar el archivo, pero el grupo al que
pertenece el dueo puede solo leerlo y los otros nada. Esto forma una
matriz, donde cada entrada de la misma tiene un 0 o 1 si esta el permiso
o no. La cuarta columna indica los permisos en base octal 

	lectura(r)		escritura(w)	ejecucin(x) En octal
dueo	    1			   1		   1		7
grupo	    1			   0		   0		4
otros       0			   0		   0		0

Si se aplica un ls -l sobre este archivo, debe desplegar

ls -l archivo
-rwxr----- .....

Esta representacin se puede dar con un nmero de tres digitos octales, en
este caso es 740. Esto se conoce como la mscara de permisos

Entonces, para aplicar estos permisos al archivo, se puede aplicar

chmod 740 archivo

	 		
Es posible que un usuario necesite dar permisos de setuid ante la ejecucin de un programa, es decir prestar su usuario o tambien su grupo.
Para esto UNIX define un cuarto digito, que se denomina el setid y que
se puede usar para prestar un id de usuario o grupo. Estos son los dgitos:

	4 - prestar id de usuario
	2 - prestar id de grupo.

Si por ejemplo, el usuario quiere sobre un programa ejecutable, dar el permiso
de set user id, y suponiendo que ya tenia la mascar 740

	chmod 4740 archivo

ls -l archivo

rwsr-----

observe la "s" en lugar de "x" para el permiso de ejecucin. Esto implicar
que el usuario que ejecute este programa, obtiene el id del dueo del archivo.


Ejercicio
	+ con cualquier archivo, aplicar los siguientes permisos
	dueo - lectura y ejecucin
	grupo  - lectura y escritura
	otros  - ejecucin
	
	utilizar el comando chmod dando la mscara de permisos.

	+ En UNIX existe un comando denominado "at" que permite 
	programar la ejecucin de un programa. Qu significa que tenga
	un permiso 4755 ?
	Otro comando es lpstat, que indica el estado de la cola de impresion.
	Este tiene permiso 4511. Qu significa esto ?
	Ambos comandos pertenecen al usuario root.

	+ Qu significa que un directorio tenga permiso 700. 

	+ checar la descripcion del comando chmod en las pginas del manual

+ Otros puntos sobre UNIX.
	+ En UNIX no importa la extensin del archivo. El nombre del
	archivo es cualquier longitud.
	+ El separador de directorios el es caracter /
	+ El caracter \ es usado por el shell para evitar que
	ciertos caracteres sean interpretados.
	+ En UNIX no existen unidades de disco. Lo que existen son
	sistemas de archivos, que son montados.
	+ Un floppy es accesado como un sistema de archivos mas. No
	hay acceso remoto a una unidad de floppy.
	+ Los programas ejecutables de UNIX no pueden ejecutarse en
	Win32 y viceversa.
	+ Una mquina con UNIX NO debe apagarse sin que el sistema operativo
	sea dado de baja.
	+ El formato de los archivos de texto UNIX son diferentes a los
	de Win32, ya que estos ltimos hacen una diferencia entre el fin
	de linea y nueva linea.
	+ Archivos de texto, codigo fuente, si se transfieren via FTP,
	deben pasarse como ascii, si son archivos binarios (imgenes,
	ejecutables UNIX) deben pasarse como archivos binarios.
	+ El comando para efectuar compresion de archivos
	
		tar cvf - <lista de archivos> | compress > archivo.tar.Z

	+ El comando para efectuar descompresion de archivos
		zcat archivo.tar.Z | tar xvf -
		(nota: tambien exixten herramientas zip para UNIX, pero
		no es probable que se encuentren en todos los UNIX)
	+ Para poder editar archivos se puede utilizar vi, pico o cualquier
	editor que grabe en formato ASCII.

RESUMEN.

Este tema trata de introducir algunos conceptos sobre como UNIX funciona.

Se defini el concepto de API y llamadas al sistema como el punto importante
para interactuar con UNIX.

Se introdujo el concepto de compilacin en lenguaje C, as como el uso
de herramientas tales como make y sccs para mantener el cdigo.

Se explico el concepto de descriptor de archivo y direccionamiento.
Tambin el uso de argumentos de la linea de comando y variables de ambiente,
que son utilizados por varios comandos de UNIX.

El concepto de usuario y grupo fue explicado, haciendo notar la importancia
de estos conceptos en el manejo de la seguridad de los recursos. Sobre
este mismo punto, se estudi el tipo de permisos sobre los recursos.

EJERCICIOS EXTRAS.

+ Tratar de optimizar el archivo Makefile, para no ser tan repetitivos en
la compilacin de cada comando.

+ Localizar el cdigo fuente de pico y bajarlo de Internet. Tratar de
compilarlo utilizando el archivo Makefile.

+ Realizar una comparacin del modelo UNIX contra NT.

+ Construir el comando myPrintf utilizando la llamada write. Investigar
como utilizar listas de argumentos variables. Solo recibir cadenas
de caracteres para simplificar el problema.

RELACION DE LLAMADAS AL SISTEMA EXPUESTAS EN ESTE TEMA.

read(2) -- lee un descriptor de archivos
write(2) -- escribe a un descriptor de archivos
getuid(2) -- obtiene el id de usuario real
getgid(2) -- obtiene el id de grupo real
geteuid(2) -- obtiene el id de usuario efectivo
getegid(2) -- obtiene el id de grupo efectivo
setuid(2) -- pone el id de usuario real
setgid(2) -- pone el id de grupo real
seteuid(2) -- pone el id de usuario efectivo
setegid(2) -- pone el id de grupo efectivo






