[BACK]Return to session.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/session.c between version 1.42.2.3 and 1.42.2.4

version 1.42.2.3, 2001/03/21 19:46:28 version 1.42.2.4, 2001/05/07 21:09:33
Line 58 
Line 58 
 #include "canohost.h"  #include "canohost.h"
 #include "session.h"  #include "session.h"
   
 #ifdef HAVE_LOGIN_CAP  
 #include <login_cap.h>  
 #endif  
   
 /* types */  /* types */
   
 #define TTYSZ 64  #define TTYSZ 64
Line 69 
Line 65 
 struct Session {  struct Session {
         int     used;          int     used;
         int     self;          int     self;
         int     extended;  
         struct  passwd *pw;          struct  passwd *pw;
         pid_t   pid;          pid_t   pid;
         /* tty */          /* tty */
Line 85 
Line 80 
         int     single_connection;          int     single_connection;
         /* proto 2 */          /* proto 2 */
         int     chanid;          int     chanid;
           int     is_subsystem;
 };  };
   
 /* func */  /* func */
Line 93 
Line 89 
 void    session_set_fds(Session *s, int fdin, int fdout, int fderr);  void    session_set_fds(Session *s, int fdin, int fdout, int fderr);
 void    session_pty_cleanup(Session *s);  void    session_pty_cleanup(Session *s);
 void    session_proctitle(Session *s);  void    session_proctitle(Session *s);
 void    do_exec_pty(Session *s, const char *command, struct passwd * pw);  void    do_exec_pty(Session *s, const char *command);
 void    do_exec_no_pty(Session *s, const char *command, struct passwd * pw);  void    do_exec_no_pty(Session *s, const char *command);
 void    do_login(Session *s, const char *command);  void    do_login(Session *s, const char *command);
 void    do_child(Session *s, const char *command);  void    do_child(Session *s, const char *command);
   void    do_motd(void);
   int     check_quietlogin(Session *s, const char *command);
   
   void    do_authenticated1(Authctxt *authctxt);
   void    do_authenticated2(Authctxt *authctxt);
   
 /* import */  /* import */
 extern ServerOptions options;  extern ServerOptions options;
 extern char *__progname;  extern char *__progname;
 extern int log_stderr;  extern int log_stderr;
 extern int debug_flag;  extern int debug_flag;
 extern u_int utmp_len;  extern u_int utmp_len;
   
 extern int startup_pipe;  extern int startup_pipe;
   extern void destroy_sensitive_data(void);
   
 /* Local Xauthority file. */  /* Local Xauthority file. */
 static char *xauthfile;  static char *xauthfile;
Line 121 
Line 122 
 static login_cap_t *lc;  static login_cap_t *lc;
 #endif  #endif
   
   void
   do_authenticated(Authctxt *authctxt)
   {
           /*
            * Cancel the alarm we set to limit the time taken for
            * authentication.
            */
           alarm(0);
           if (startup_pipe != -1) {
                   close(startup_pipe);
                   startup_pipe = -1;
           }
   #ifdef HAVE_LOGIN_CAP
           if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {
                   error("unable to get login class");
                   return;
           }
   #ifdef BSD_AUTH
           if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) {
                   packet_disconnect("Approval failure for %s",
                       authctxt->pw->pw_name);
           }
   #endif
   #endif
           /* setup the channel layer */
           if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
                   channel_permit_all_opens();
   
           if (compat20)
                   do_authenticated2(authctxt);
           else
                   do_authenticated1(authctxt);
   }
   
 /*  /*
  * Remove local Xauthority file.   * Remove local Xauthority file.
  */   */
Line 170 
Line 205 
  * are requested, etc.   * are requested, etc.
  */   */
 void  void
 do_authenticated(struct passwd * pw)  do_authenticated1(Authctxt *authctxt)
 {  {
         Session *s;          Session *s;
         int type, fd;  
         int compression_level = 0, enable_compression_after_reply = 0;  
         int have_pty = 0;  
         char *command;          char *command;
         int n_bytes;          int success, type, fd, n_bytes, plen, screen_flag, have_pty = 0;
         int plen;          int compression_level = 0, enable_compression_after_reply = 0;
         u_int proto_len, data_len, dlen;          u_int proto_len, data_len, dlen;
         int screen_flag;  
   
         /*  
          * Cancel the alarm we set to limit the time taken for  
          * authentication.  
          */  
         alarm(0);  
         if (startup_pipe != -1) {  
                 close(startup_pipe);  
                 startup_pipe = -1;  
         }  
   
         s = session_new();          s = session_new();
         s->pw = pw;          s->pw = authctxt->pw;
   
         if (!no_port_forwarding_flag && options.allow_tcp_forwarding)  
                 channel_permit_all_opens();  
   
 #ifdef HAVE_LOGIN_CAP  
         if ((lc = login_getclass(pw->pw_class)) == NULL) {  
                 error("unable to get login class");  
                 return;  
         }  
 #endif  
   
         /*          /*
          * We stay in this loop until the client requests to execute a shell           * We stay in this loop until the client requests to execute a shell
          * or a command.           * or a command.
          */           */
         for (;;) {          for (;;) {
                 int success = 0;                  success = 0;
   
                 /* Get a packet from the client. */                  /* Get a packet from the client. */
                 type = packet_read(&plen);                  type = packet_read(&plen);
Line 247 
Line 258 
                                 break;                                  break;
                         }                          }
                         fatal_add_cleanup(pty_cleanup_proc, (void *)s);                          fatal_add_cleanup(pty_cleanup_proc, (void *)s);
                         pty_setowner(pw, s->tty);                          pty_setowner(s->pw, s->tty);
   
                         /* Get TERM from the packet.  Note that the value may be of arbitrary length. */                          /* Get TERM from the packet.  Note that the value may be of arbitrary length. */
                         s->term = packet_get_string(&dlen);                          s->term = packet_get_string(&dlen);
Line 322 
Line 333 
                         /* Setup to always have a local .Xauthority. */                          /* Setup to always have a local .Xauthority. */
                         xauthfile = xmalloc(MAXPATHLEN);                          xauthfile = xmalloc(MAXPATHLEN);
                         strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);                          strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
                         temporarily_use_uid(pw->pw_uid);                          temporarily_use_uid(s->pw);
                         if (mkdtemp(xauthfile) == NULL) {                          if (mkdtemp(xauthfile) == NULL) {
                                 restore_uid();                                  restore_uid();
                                 error("private X11 dir: mkdtemp %s failed: %s",                                  error("private X11 dir: mkdtemp %s failed: %s",
Line 347 
Line 358 
                                 break;                                  break;
                         }                          }
                         debug("Received authentication agent forwarding request.");                          debug("Received authentication agent forwarding request.");
                         success = auth_input_request_forwarding(pw);                          success = auth_input_request_forwarding(s->pw);
                         break;                          break;
   
                 case SSH_CMSG_PORT_FORWARD_REQUEST:                  case SSH_CMSG_PORT_FORWARD_REQUEST:
Line 360 
Line 371 
                                 break;                                  break;
                         }                          }
                         debug("Received TCP/IP port forwarding request.");                          debug("Received TCP/IP port forwarding request.");
                         channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);                          channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
                         success = 1;                          success = 1;
                         break;                          break;
   
Line 385 
Line 396 
                                 debug("Forced command '%.500s'", forced_command);                                  debug("Forced command '%.500s'", forced_command);
                         }                          }
                         if (have_pty)                          if (have_pty)
                                 do_exec_pty(s, command, pw);                                  do_exec_pty(s, command);
                         else                          else
                                 do_exec_no_pty(s, command, pw);                                  do_exec_no_pty(s, command);
   
                         if (command != NULL)                          if (command != NULL)
                                 xfree(command);                                  xfree(command);
Line 421 
Line 432 
  * setting up file descriptors and such.   * setting up file descriptors and such.
  */   */
 void  void
 do_exec_no_pty(Session *s, const char *command, struct passwd * pw)  do_exec_no_pty(Session *s, const char *command)
 {  {
         int pid;          int pid;
   
Line 509 
Line 520 
         close(perr[1]);          close(perr[1]);
   
         if (compat20) {          if (compat20) {
                 session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);                  session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
         } else {          } else {
                 /* Enter the interactive session. */                  /* Enter the interactive session. */
                 server_loop(pid, pin[1], pout[0], perr[0]);                  server_loop(pid, pin[1], pout[0], perr[0]);
                 /* server_loop has closed pin[1], pout[1], and perr[1]. */                  /* server_loop has closed pin[1], pout[0], and perr[0]. */
         }          }
 #else /* USE_PIPES */  #else /* USE_PIPES */
         /* We are the parent.  Close the child sides of the socket pairs. */          /* We are the parent.  Close the child sides of the socket pairs. */
Line 525 
Line 536 
          * handle the case that fdin and fdout are the same.           * handle the case that fdin and fdout are the same.
          */           */
         if (compat20) {          if (compat20) {
                 session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);                  session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
         } else {          } else {
                 server_loop(pid, inout[1], inout[1], err[1]);                  server_loop(pid, inout[1], inout[1], err[1]);
                 /* server_loop has closed inout[1] and err[1]. */                  /* server_loop has closed inout[1] and err[1]. */
Line 540 
Line 551 
  * lastlog, and other such operations.   * lastlog, and other such operations.
  */   */
 void  void
 do_exec_pty(Session *s, const char *command, struct passwd * pw)  do_exec_pty(Session *s, const char *command)
 {  {
         int fdout, ptyfd, ttyfd, ptymaster;          int fdout, ptyfd, ttyfd, ptymaster;
         pid_t pid;          pid_t pid;
Line 617 
Line 628 
         }          }
 }  }
   
 const char *  
 get_remote_name_or_ip(void)  
 {  
         static const char *remote = "";  
         if (utmp_len > 0)  
                 remote = get_canonical_hostname(options.reverse_mapping_check);  
         if (utmp_len == 0 || strlen(remote) > utmp_len)  
                 remote = get_remote_ipaddr();  
         return remote;  
 }  
   
 /* administrative, login(1)-like work */  /* administrative, login(1)-like work */
 void  void
 do_login(Session *s, const char *command)  do_login(Session *s, const char *command)
 {  {
         FILE *f;  
         char *time_string;          char *time_string;
         char buf[256];  
         char hostname[MAXHOSTNAMELEN];          char hostname[MAXHOSTNAMELEN];
         socklen_t fromlen;          socklen_t fromlen;
         struct sockaddr_storage from;          struct sockaddr_storage from;
         struct stat st;  
         time_t last_login_time;          time_t last_login_time;
         struct passwd * pw = s->pw;          struct passwd * pw = s->pw;
         pid_t pid = getpid();          pid_t pid = getpid();
Line 658 
Line 655 
         }          }
   
         /* Get the time and hostname when the user last logged in. */          /* Get the time and hostname when the user last logged in. */
         hostname[0] = '\0';          if (options.print_lastlog) {
         last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,                  hostname[0] = '\0';
             hostname, sizeof(hostname));                  last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
                       hostname, sizeof(hostname));
           }
   
         /* Record that there was a login on that tty from the remote host. */          /* Record that there was a login on that tty from the remote host. */
         record_login(pid, s->tty, pw->pw_name, pw->pw_uid,          record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
             get_remote_name_or_ip(), (struct sockaddr *)&from);              get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
               (struct sockaddr *)&from);
   
         /* Done if .hushlogin exists or a command given. */          if (check_quietlogin(s, command))
         if (command != NULL)  
                 return;                  return;
         snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);  
 #ifdef HAVE_LOGIN_CAP          if (options.print_lastlog && last_login_time != 0) {
         if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)  
 #else  
         if (stat(buf, &st) >= 0)  
 #endif  
                 return;  
         if (last_login_time != 0) {  
                 time_string = ctime(&last_login_time);                  time_string = ctime(&last_login_time);
                 if (strchr(time_string, '\n'))                  if (strchr(time_string, '\n'))
                         *strchr(time_string, '\n') = 0;                          *strchr(time_string, '\n') = 0;
Line 685 
Line 678 
                 else                  else
                         printf("Last login: %s from %s\r\n", time_string, hostname);                          printf("Last login: %s from %s\r\n", time_string, hostname);
         }          }
   
           do_motd();
   }
   
   /*
    * Display the message of the day.
    */
   void
   do_motd(void)
   {
           FILE *f;
           char buf[256];
   
         if (options.print_motd) {          if (options.print_motd) {
 #ifdef HAVE_LOGIN_CAP  #ifdef HAVE_LOGIN_CAP
                 f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",                  f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
Line 700 
Line 706 
         }          }
 }  }
   
   
 /*  /*
    * Check for quiet login, either .hushlogin or command given.
    */
   int
   check_quietlogin(Session *s, const char *command)
   {
           char buf[256];
           struct passwd * pw = s->pw;
           struct stat st;
   
           /* Return 1 if .hushlogin exists or a command given. */
           if (command != NULL)
                   return 1;
           snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
   #ifdef HAVE_LOGIN_CAP
           if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
                   return 1;
   #else
           if (stat(buf, &st) >= 0)
                   return 1;
   #endif
           return 0;
   }
   
   /*
  * Sets the value of the given variable in the environment.  If the variable   * Sets the value of the given variable in the environment.  If the variable
  * already exists, its value is overriden.   * already exists, its value is overriden.
  */   */
Line 800 
Line 831 
         char *argv[10];          char *argv[10];
         int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;          int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;
   
           /* remove hostkey from the child's memory */
           destroy_sensitive_data();
   
         /* login(1) is only called if we execute the login shell */          /* login(1) is only called if we execute the login shell */
         if (options.use_login && command != NULL)          if (options.use_login && command != NULL)
                 options.use_login = 0;                  options.use_login = 0;
Line 831 
Line 865 
                             (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {                              (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
                                 perror("unable to set user context");                                  perror("unable to set user context");
                                 exit(1);                                  exit(1);
   
                         }                          }
 #else  #else
                         if (setlogin(pw->pw_name) < 0)                          if (setlogin(pw->pw_name) < 0)
Line 848 
Line 881 
                         endgrent();                          endgrent();
   
                         /* Permanently switch to the desired uid. */                          /* Permanently switch to the desired uid. */
                         permanently_set_uid(pw->pw_uid);                          permanently_set_uid(pw);
 #endif  #endif
                 }                  }
                 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)                  if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
Line 960 
Line 993 
         }          }
         /* we have to stash the hostname before we close our socket. */          /* we have to stash the hostname before we close our socket. */
         if (options.use_login)          if (options.use_login)
                 hostname = get_remote_name_or_ip();                  hostname = get_remote_name_or_ip(utmp_len,
                       options.reverse_mapping_check);
         /*          /*
          * Close the connection descriptors; note that this is the child, and           * Close the connection descriptors; note that this is the child, and
          * the server will still have the socket open, and it is important           * the server will still have the socket open, and it is important
Line 1017 
Line 1051 
          * in this order).           * in this order).
          */           */
         if (!options.use_login) {          if (!options.use_login) {
                 if (stat(_PATH_SSH_USER_RC, &st) >= 0) {                  /* ignore _PATH_SSH_USER_RC for subsystems */
                   if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
                         if (debug_flag)                          if (debug_flag)
                                 fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,                                  fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
                                     _PATH_SSH_USER_RC);                                      _PATH_SSH_USER_RC);
Line 1085 
Line 1120 
                 else                  else
                         cp = shell;                          cp = shell;
         }          }
   
           /* restore SIGPIPE for child */
           signal(SIGPIPE,  SIG_DFL);
   
         /*          /*
          * If we have no command, execute the shell.  In this case, the shell           * If we have no command, execute the shell.  In this case, the shell
          * name to be passed in argv[0] is preceded by '-' to indicate that           * name to be passed in argv[0] is preceded by '-' to indicate that
Line 1168 
Line 1207 
         for(i = 0; i < MAX_SESSIONS; i++) {          for(i = 0; i < MAX_SESSIONS; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 if (! s->used) {                  if (! s->used) {
                         s->pid = 0;                          memset(s, 0, sizeof(*s));
                         s->extended = 0;  
                         s->chanid = -1;                          s->chanid = -1;
                         s->ptyfd = -1;                          s->ptyfd = -1;
                         s->ttyfd = -1;                          s->ttyfd = -1;
                         s->term = NULL;  
                         s->pw = NULL;  
                         s->display = NULL;  
                         s->screen = 0;  
                         s->auth_data = NULL;  
                         s->auth_proto = NULL;  
                         s->used = 1;                          s->used = 1;
                         s->pw = NULL;  
                         debug("session_new: session %d", i);                          debug("session_new: session %d", i);
                         return s;                          return s;
                 }                  }
Line 1267 
Line 1298 
 session_pty_req(Session *s)  session_pty_req(Session *s)
 {  {
         u_int len;          u_int len;
         char *term_modes;       /* encoded terminal modes */          int n_bytes;
   
         if (no_pty_flag)          if (no_pty_flag)
                 return 0;                  return 0;
Line 1278 
Line 1309 
         s->row = packet_get_int();          s->row = packet_get_int();
         s->xpixel = packet_get_int();          s->xpixel = packet_get_int();
         s->ypixel = packet_get_int();          s->ypixel = packet_get_int();
         term_modes = packet_get_string(&len);  
         packet_done();  
   
         if (strcmp(s->term, "") == 0) {          if (strcmp(s->term, "") == 0) {
                 xfree(s->term);                  xfree(s->term);
Line 1292 
Line 1321 
                 s->ptyfd = -1;                  s->ptyfd = -1;
                 s->ttyfd = -1;                  s->ttyfd = -1;
                 error("session_pty_req: session %d alloc failed", s->self);                  error("session_pty_req: session %d alloc failed", s->self);
                 xfree(term_modes);  
                 return 0;                  return 0;
         }          }
         debug("session_pty_req: session %d alloc %s", s->self, s->tty);          debug("session_pty_req: session %d alloc %s", s->self, s->tty);
Line 1305 
Line 1333 
         /* Get window size from the packet. */          /* Get window size from the packet. */
         pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);          pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
   
           /* Get tty modes from the packet. */
           tty_parse_modes(s->ttyfd, &n_bytes);
           packet_done();
   
         session_proctitle(s);          session_proctitle(s);
   
         /* XXX parse and set terminal modes */  
         xfree(term_modes);  
         return 1;          return 1;
 }  }
   
Line 1326 
Line 1356 
         for (i = 0; i < options.num_subsystems; i++) {          for (i = 0; i < options.num_subsystems; i++) {
                 if(strcmp(subsys, options.subsystem_name[i]) == 0) {                  if(strcmp(subsys, options.subsystem_name[i]) == 0) {
                         debug("subsystem: exec() %s", options.subsystem_command[i]);                          debug("subsystem: exec() %s", options.subsystem_command[i]);
                         do_exec_no_pty(s, options.subsystem_command[i], s->pw);                          s->is_subsystem = 1;
                           do_exec_no_pty(s, options.subsystem_command[i]);
                         success = 1;                          success = 1;
                 }                  }
         }          }
Line 1373 
Line 1404 
         }          }
         xauthfile = xmalloc(MAXPATHLEN);          xauthfile = xmalloc(MAXPATHLEN);
         strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);          strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
         temporarily_use_uid(s->pw->pw_uid);          temporarily_use_uid(s->pw);
         if (mkdtemp(xauthfile) == NULL) {          if (mkdtemp(xauthfile) == NULL) {
                 restore_uid();                  restore_uid();
                 error("private X11 dir: mkdtemp %s failed: %s",                  error("private X11 dir: mkdtemp %s failed: %s",
Line 1400 
Line 1431 
         /* if forced_command == NULL, the shell is execed */          /* if forced_command == NULL, the shell is execed */
         char *shell = forced_command;          char *shell = forced_command;
         packet_done();          packet_done();
         s->extended = 1;  
         if (s->ttyfd == -1)          if (s->ttyfd == -1)
                 do_exec_no_pty(s, shell, s->pw);                  do_exec_no_pty(s, shell);
         else          else
                 do_exec_pty(s, shell, s->pw);                  do_exec_pty(s, shell);
         return 1;          return 1;
 }  }
   
Line 1419 
Line 1449 
                 command = forced_command;                  command = forced_command;
                 debug("Forced command '%.500s'", forced_command);                  debug("Forced command '%.500s'", forced_command);
         }          }
         s->extended = 1;  
         if (s->ttyfd == -1)          if (s->ttyfd == -1)
                 do_exec_no_pty(s, command, s->pw);                  do_exec_no_pty(s, command);
         else          else
                 do_exec_pty(s, command, s->pw);                  do_exec_pty(s, command);
         if (forced_command == NULL)          if (forced_command == NULL)
                 xfree(command);                  xfree(command);
         return 1;          return 1;
Line 1470 
Line 1499 
             s->self, id, rtype, reply);              s->self, id, rtype, reply);
   
         /*          /*
          * a session is in LARVAL state until a shell           * a session is in LARVAL state until a shell, a command
          * or programm is executed           * or a subsystem is executed
          */           */
         if (c->type == SSH_CHANNEL_LARVAL) {          if (c->type == SSH_CHANNEL_LARVAL) {
                 if (strcmp(rtype, "shell") == 0) {                  if (strcmp(rtype, "shell") == 0) {
Line 1684 
Line 1713 
 void  void
 do_authenticated2(Authctxt *authctxt)  do_authenticated2(Authctxt *authctxt)
 {  {
         /*  
          * Cancel the alarm we set to limit the time taken for  
          * authentication.  
          */  
         alarm(0);  
         if (startup_pipe != -1) {  
                 close(startup_pipe);  
                 startup_pipe = -1;  
         }  
         if (!no_port_forwarding_flag && options.allow_tcp_forwarding)  
                 channel_permit_all_opens();  
 #ifdef HAVE_LOGIN_CAP  
         if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {  
                 error("unable to get login class");  
                 return;  
         }  
 #endif  
         server_loop2();          server_loop2();
         if (xauthfile)          if (xauthfile)
                 xauthfile_cleanup_proc(NULL);                  xauthfile_cleanup_proc(NULL);

Legend:
Removed from v.1.42.2.3  
changed lines
  Added in v.1.42.2.4