2013-03-16 3 views
0

Je veux savoir comment rsh exécute n'importe quelle commande. J'utilise le paquet netkit-rsh-0.17. Mon système d'exploitation est centOS.Explique comment fonctionne la fonction doit() dans rshd.c

Dans le répertoire rshd, rshd.c exécute la tâche pour exécuter toute commande sur le serveur. Dans ce fichier, doit() est la fonction principale qui effectue toute la tâche.

Questions,

  1. Qu'est-ce pwd->pw_dir, pwd->pw_uid, pwd->pw_shell moyens dans ce code?
  2. Ce que pv fait dans ce.

Expliquez-moi en utilisant la commande rsh localhost ulimit -n.

Doït()

static void 
doit(struct sockaddr_in *fromp) 
{ 
    char cmdbuf[ARG_MAX+1]; 
    const char *theshell, *shellname; 
    char locuser[16], remuser[16]; 
    struct passwd *pwd; 
    int sock = -1; 
    const char *hostname; 
    u_short port; 
    int pv[2], pid, ifd; 

    signal(SIGINT, SIG_DFL); 
    signal(SIGQUIT, SIG_DFL); 
    signal(SIGTERM, SIG_DFL); 

    alarm(60); 
    port = getint(); 
    alarm(0); 

    if (port != 0) { 
     int lport = IPPORT_RESERVED - 1; 
     sock = rresvport(&lport); 
     if (sock < 0) { 
      syslog(LOG_ERR, "can't get stderr port: %m"); 
      exit(1); 
     } 
     if (port >= IPPORT_RESERVED) { 
      syslog(LOG_ERR, "2nd port not reserved\n"); 
      exit(1); 
     } 
     fromp->sin_port = htons(port); 
     if (connect(sock, (struct sockaddr *)fromp, 
       sizeof(*fromp)) < 0) { 
      syslog(LOG_INFO, "connect second port: %m"); 
      exit(1); 
     } 
    } 

#if 0 
    /* We're running from inetd; socket is already on 0, 1, 2 */ 
    dup2(f, 0); 
    dup2(f, 1); 
    dup2(f, 2); 
#endif 

    getstr(remuser, sizeof(remuser), "remuser"); 
    getstr(locuser, sizeof(locuser), "locuser"); 
    getstr(cmdbuf, sizeof(cmdbuf), "command"); 
    if (!strcmp(locuser, "root")) paranoid = 1; 

    hostname = findhostname(fromp, remuser, locuser, cmdbuf); 

    setpwent(); 
    pwd = doauth(remuser, hostname, locuser); 
    if (pwd == NULL) { 
     fail("Permission denied.\n", 
      remuser, hostname, locuser, cmdbuf); 
    } 

    if (chdir(pwd->pw_dir) < 0) { 
     chdir("/"); 
     /* 
     * error("No remote directory.\n"); 
     * exit(1); 
     */ 
    } 


    if (pwd->pw_uid != 0 && !access(_PATH_NOLOGIN, F_OK)) { 
     error("Logins currently disabled.\n"); 
     exit(1); 
    } 

    (void) write(2, "\0", 1); 
    sent_null = 1; 

    if (port) { 
     if (pipe(pv) < 0) { 
      error("Can't make pipe.\n"); 
      exit(1); 
     } 
     pid = fork(); 
     if (pid == -1) { 
      error("Can't fork; try again.\n"); 
      exit(1); 
     } 
     if (pid) { 
      close(0); 
      close(1); 
      close(2); 
      close(pv[1]); 
      stderr_parent(sock, pv[0], pid); 
      /* NOTREACHED */ 
     } 
     setpgrp(); 
     close(sock); 
     close(pv[0]); 
     dup2(pv[1], 2); 
     close(pv[1]); 
    } 
    theshell = pwd->pw_shell; 
    if (!theshell || !*theshell) { 
     /* shouldn't we deny access? */ 
     theshell = _PATH_BSHELL; 
    } 

#if BSD > 43 
    if (setlogin(pwd->pw_name) < 0) { 
     syslog(LOG_ERR, "setlogin() failed: %m"); 
    } 
#endif 
#ifndef USE_PAM 
    /* if PAM, already done */ 
    if (setgid(pwd->pw_gid)) { 
     syslog(LOG_ERR, "setgid: %m"); 
     exit(1); 
    } 
    if (initgroups(pwd->pw_name, pwd->pw_gid)) { 
     syslog(LOG_ERR, "initgroups: %m"); 
     exit(1); 
    } 
#endif 
    if (setuid(pwd->pw_uid)) { 
     syslog(LOG_ERR, "setuid: %m"); 
     exit(1); 
    } 
    environ = envinit; 

    strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 
    homedir[sizeof(homedir)-1] = 0; 

    strcat(path, _PATH_DEFPATH); 

    strncat(shell, theshell, sizeof(shell)-7); 
    shell[sizeof(shell)-1] = 0; 

    strncat(username, pwd->pw_name, sizeof(username)-6); 
    username[sizeof(username)-1] = 0; 

    shellname = strrchr(theshell, '/'); 
    if (shellname) shellname++; 
    else shellname = theshell; 

    endpwent(); 
    if (paranoid) { 
     syslog(LOG_INFO|LOG_AUTH, "%[email protected]%s as %s: cmd='%s'", 
      remuser, hostname, locuser, cmdbuf); 
    } 

    /* 
    * Close all fds, in case libc has left fun stuff like 
    * /etc/shadow open. 
    */ 
    for (ifd = getdtablesize()-1; ifd > 2; ifd--) close(ifd); 

    execl(theshell, shellname, "-c", cmdbuf, 0); 
    perror(theshell); 
    exit(1); 
} 
+0

Lisez la page de manuel sur 'exec (3)'. Il remplace le programme en cours d'exécution par un nouveau. – vonbrand

+0

J'ai lu cela, mais comment cela peut-il effectuer toute la tâche dans la fonction ci-dessus en utilisant la commande ci-dessus écrite en question, s'il vous plaît. – devsda

+3

Il s'agit d'une question de programmation système de première année. Toutes les fonctions du code ci-dessus ont des pages 'man'. – millimoose

Répondre

5

struct passwd est décrite dans Posix, en pwd.h. C'est une structure utilisée pour stocker les entrées /etc/passwd pour un utilisateur donné. Les trois que vous mentionnez sont les suivants:

  • uid_t pw_uid
    ID utilisateur numérique.
  • char *pw_dir
    Répertoire de travail initial. (Répertoire principal.)
  • char *pw_shell
    Programme à utiliser comme shell. (Shell par défaut pour l'utilisateur.)

La fonction doauth référencé dans le code ci-dessus probablement soit des appels getpwent ou qui simulent à remplir les valeurs appropriées pour l'utilisateur sur le système distant.

pv est une paire de descripteurs de fichiers représentant des tuyaux connectés, mis en place par pipe(). pv[0] est le "côté de lecture", pv[1] le "côté d'écriture". Tout ce qui est écrit au pv[1] peut être lu à partir de pv[0].

Dans le code ci-dessus, le processus parent fait:

close(pv[1]); 
stderr_parent(sock, pv[0], pid); 

qui ferme le côté d'écriture, et, je suppose, les fils du côté de lecture à (un) des douilles utilisées pour communiquer entre le hôtes.

Le processus enfant d'autre part ce que cela: Donc, fondamentalement

close(pv[0]); // close the read side 
dup2(pv[1], 2); // clone the write side to fd n° 2 (stderr) 
close(pv[1]); // close the original write side (now only 
       // writable through fd n° 2 

, flux stderr de l'enfant est maintenant connecté à un flux réseau au client.

Le reste du code aseptise essentiellement l'environnement (variables d'environnement et répertoire de travail), vérifie les autorisations, règle le approprié uid/gid et exécute enfin la commande que l'utilisateur a voulu exécuter à l'aide execl() via un shell. La commande réelle exécutée sur le système distant sera quelque chose comme /bin/sh -c <user command string>.
donc avec votre exemple, en supposant par exemple que votre shell de l'utilisateur dans /etc/passwd est /bin/bash, l'appel execl se traduira par l'exécution de cette:

/bin/bash -c 'ulimit -n' 

(Citations depuis la commande utilisateur est un seul argument dans l'appel execl, il n'est pas tokenized.)

+0

Explication excellente. J'attendais une si belle explication depuis longtemps de ce forum. Merci. Maintenant, j'essaie de connecter cette solution à mon problème principal. C'est sur le lien donné http://serverfault.com/questions/487426/why-ulimit-shows-different-outputs Si je vais trouver un doute, je vous contacterai. +1 pour votre explication – devsda

+0

@ jhamb Notez que rshd est le service. Cela signifie que ce que Mat appelle "l'utilisateur distant" est ce que le code appelle locuser. De même, le système distant est celui qui exécute localement ce même code. – jlliagre

Questions connexes