$NetBSD: patch-af,v 1.10 2000/03/20 02:25:50 itojun Exp $

--- sshd.c-	Wed May 12 20:19:29 1999
+++ sshd.c	Mon Mar 20 09:57:30 2000
@@ -511,7 +511,7 @@
 #include "firewall.h"   /* TIS authsrv authentication */
 #endif
 
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
 #include <login_cap.h>
 #endif
 
@@ -537,15 +537,26 @@
 #define O_NOCTTY        0
 #endif
 
-#ifdef KERBEROS
 #ifdef KRB5
 #include <krb5.h>
 /* Global the contexts */
 krb5_context ssh_context = 0;
 krb5_auth_context auth_context = 0;
 #endif /* KRB5 */
-char *ticket = "none\0";
-#endif /* KERBEROS */
+
+#ifdef KRB4
+#include <sys/param.h>
+#include <krb.h>
+#ifdef AFS
+#include <kafs.h>
+/* Local Xauthority file. */
+char *xauthfile = NULL;
+#endif /* AFS */
+#endif /* KRB4 */
+
+#if defined(KRB5) || defined(KRB4)
+char *ticket = NULL;
+#endif /* KRB5 || KRB4 */
 
 /* Server configuration options. */
 ServerOptions options;
@@ -1115,7 +1126,6 @@
       /* Arrange SIGCHLD to be caught. */
       signal(SIGCHLD, main_sigchld_handler);
 
-#ifdef KERBEROS
 #ifdef KRB5
       /* Initialize contexts and setup replay cache */
       if (!ssh_context)
@@ -1128,7 +1138,6 @@
           krb5_init_ets(ssh_context);
         }
 #endif
-#endif
 
       /* Stay listening for connections until the system crashes or the
          daemon is killed with a signal. */
@@ -1407,6 +1416,16 @@
   /* Try to remove authentication socket and directory */
   auth_delete_socket(NULL);
   
+#ifdef KRB4
+  /* Cleanup user's ticket cache file. */
+  if (options.kerberos_ticket_cleanup)
+    (void) dest_tkt();
+#ifdef AFS
+  /* Cleanup user's local Xauthority file. */
+  if (xauthfile) unlink(xauthfile);
+#endif /* AFS */
+#endif /* KRB4 */
+  
   /* The connection has been terminated. */
   log_msg("Closing connection to %.100s", get_remote_ipaddr());
   packet_close();
@@ -1470,17 +1489,17 @@
   if (options.tis_authentication)
     auth_mask |= 1 << SSH_AUTH_TIS;
 #endif
-#ifdef KERBEROS
-#ifdef KRB5
+#if defined(KRB4) || defined(KRB5)
   if (options.kerberos_authentication)
     auth_mask |= 1 << SSH_AUTH_KERBEROS;
 #endif
-#endif
-#ifdef KERBEROS_TGT_PASSING
-#ifdef KRB5
+#if defined(AFS) || defined(KRB5)
   if (options.kerberos_tgt_passing)
     auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
 #endif
+#ifdef AFS
+  if (options.afs_token_passing)
+    auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
 #endif
   if (options.password_authentication)
     auth_mask |= 1 << SSH_AUTH_PASSWORD;
@@ -1677,7 +1696,7 @@
     /* XXX No days_before_password_expires calculation here */
   }
 #endif /* HAVE_USERSEC_H */
-#ifdef HAVE_ETC_SHADOW
+#if defined(HAVE_ETC_SHADOW) && !defined(KRB4) && !defined(KRB5)
   {
     struct spwd *sp;
     
@@ -1783,56 +1802,62 @@
     endspent();
   }
 #endif /* HAVE_ETC_SHADOW */
-#ifdef __FreeBSD__
-  {
+/* Net2,BSD4.4,BSD/OS,NetBSD,FreeBSD and OpenBSD all define BSD4_4
+   man passwd(5) says that format has changed since BSD4.3
+ */
+#ifdef BSD4_4
+  if(pwd->pw_change || pwd->pw_expire) {
     time_t currtime;
     
-    if (pwd->pw_change || pwd->pw_expire)
       currtime = time(NULL);
     
     /*
      * Check for an expired password
      */
-    if (pwd->pw_change && pwd->pw_change <= currtime)
+
+    if (pwd->pw_change)
       {
-        debug("Account %.100s's password is too old - forced to change.",
-              user);
-        if (options.forced_passwd_change)
+       /* PASSWD_CHGNOW seems to be -1 for now but... */
+       if (
+#if defined(PASSWD_CHGNOW) && PASSWD_CHGNOW > 0
+           pwd->pw_change == PASSWD_CHGNOW ||
+#endif
+           pwd->pw_change <= currtime)
           {
-            forced_command = xmalloc(sizeof(PASSWD_PATH) + strlen(user) + 2);
-            snprintf(forced_command, sizeof(PASSWD_PATH) + strlen(user) + 2,
-                     "%.100s %.100s", PASSWD_PATH, user);
+	   packet_send_debug("Password has expired");
+	   if(options.forced_passwd_change)
+	     {
+	       debug("Account %.99s's password is too old - change forced.",
+		     user);
+	       forced_command = xmalloc(sizeof(PASSWD_PATH) +
+					strlen(user) + 1);
+	       sprintf(forced_command, "%s %s", PASSWD_PATH, user);
           }
         else
           {
             return 0;
           }
       }
-    else
-      {
-        if (pwd->pw_change)
-          {
+#ifdef PASSWD_CHGNOW
+      if(pwd->pw_change != PASSWD_CHGNOW)
             days_before_password_expires = (pwd->pw_change - currtime) / 86400;
-          }
+#endif
       }
     
     /*
      * Check for expired account
      */
-    if (pwd->pw_expire && pwd->pw_expire <= currtime)
+    if (pwd->pw_expire)
       {
-        debug("Account %.100s has expired - access denied.", user);
+        if (pwd->pw_expire <= currtime)
+          {
+            packet_send_debug("Account has expired");
         return 0;
       }
-    else
-      {
-        if (pwd->pw_expire)
-          {
             days_before_account_expires = (pwd->pw_expire - currtime) / 86400;
           }
       }
-  }
-#endif  /* !FreeBSD */
+#endif  /* !BSD4_4 */
 
 #ifdef HAVE_HPUX_TCB_AUTH
   {
@@ -2039,7 +2064,7 @@
           }
     }
   
-  /* Check whether logins are deneid for this group. */
+  /* Check whether logins are denied for this group. */
   grp = getgrgid(pwd->pw_gid);
   if (grp)
     group = grp->gr_name;
@@ -2151,12 +2176,12 @@
   unsigned int client_host_key_bits;
   MP_INT client_host_key_e, client_host_key_n;
   int password_attempts = 0;
-#if defined(KERBEROS) && defined(KRB5)
+#ifdef KRB5
   char kuser[256];
   krb5_principal client = 0, tkt_client = 0;
   krb5_data krb5data;
-#endif /* defined(KERBEROS) && defined(KRB5) */
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#endif /* KRB5 */
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
   login_cap_t *lc;
   const char *hostname;
   const char *ipaddr;
@@ -2167,10 +2192,18 @@
   ipaddr = get_remote_ipaddr();
 #endif /* HAVE_LOGIN_CAP_H */
 
+#ifdef AFS
+  /* If machine has AFS, set process authentication group. */
+  if (k_hasafs()) {
+    k_setpag();
+    k_unlog();
+  }
+#endif /* AFS */
+       
   if (strlen(user) > 255)
     do_authentication_fail_loop();
 
-#if defined(KERBEROS) && defined(KRB5)
+#ifdef KRB5
   /* For KRB5 allow the user to input fully qualified name i.e.
      "username@realm" as the local user name. Then use this name to call
      out to krb5_aname_to_localname to find if there is a localname
@@ -2203,7 +2236,7 @@
     }
   else 
     krb5_parse_name(ssh_context, user, &client);
-#endif /* defined(KERBEROS) && defined(KRB5) */
+#endif /* KRB5 */
                          
   /* Verify that the user is a valid user.  We disallow usernames starting
      with any characters that are commonly used to start NIS entries. */
@@ -2218,11 +2251,11 @@
   pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
   pwcopy.pw_uid = pw->pw_uid;
   pwcopy.pw_gid = pw->pw_gid;
-#if (defined (__bsdi__) && _BSDI_VERSION >= 199510) || (defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H))
+#ifdef BSD4_4
   pwcopy.pw_class = xstrdup(pw->pw_class);
   pwcopy.pw_change = pw->pw_change;
   pwcopy.pw_expire = pw->pw_expire;
-#endif /*  __bsdi__  && _BSDI_VERSION >= 199510 */
+#endif /*  BSD4_4 */
   pwcopy.pw_dir = xstrdup(pw->pw_dir);
   pwcopy.pw_shell = xstrdup(pw->pw_shell);
   pw = &pwcopy;
@@ -2241,11 +2274,11 @@
 
   debug("Attempting authentication for %.100s.", user);
 
-#if defined (KERBEROS) && defined (KRB5)
+  /* If the user has no password, accept authentication immediately. */
+#ifdef KRB5
   if (!options.kerberos_authentication && options.password_authentication &&
       auth_password(user, "", 0))
-#else /* defined(KERBEROS) && defined(KRB5) */
-  /* If the user has no password, accept authentication immediately. */
+#else /* KRB5 */
 #if defined (HAVE_SIA)
   /* For SIA, only call auth_password() here if the user really
      has no password.  Otherwise, the call would generate misleading
@@ -2254,9 +2287,13 @@
   if (options.password_authentication && sia_no_password(user) &&
       auth_password(user, ""))
 #else /* defined(HAVE_SIA) */
-  if (options.password_authentication && auth_password(user, ""))
+  if (options.password_authentication &&
+#ifdef KRB4
+      options.kerberos_or_local_passwd &&
+#endif /* KRB4 */
+      auth_password(user, ""))
 #endif /* defined(HAVE_SIA) */
-#endif /* defined(KERBEROS) && defined(KRB5) */
+#endif /* KRB5 */
     {
       /* Authentication with empty password succeeded. */
       debug("Login for user %.100s accepted without authentication.", user);
@@ -2281,34 +2318,61 @@
       /* Process the packet. */
       switch (type)
         {
-#ifdef KERBEROS_TGT_PASSING
-#ifdef KRB5
+#if defined(KRB5) || defined(AFS)
         case SSH_CMSG_HAVE_KERBEROS_TGT:
+#ifdef KRB5
           if (!options.kerberos_tgt_passing || 
               (!(options.kerberos_authentication || 
                  options.password_authentication ||
                  options.rsa_authentication)))
+#else /* KRB5 */
+	  if (!options.kerberos_tgt_passing)
+#endif /* KRB5 */
             {
               packet_get_all();
               log_msg("Kerberos tgt passing disabled.");
               break;
             }
-          
+#ifdef KRB5
           /* Accept Kerberos tgt. */
           krb5data.data = packet_get_string((unsigned int *) &krb5data.length);
           
-          if (!auth_kerberos_tgt(user, &krb5data, client) ||
+          if (!auth_krb5_tgt(user, &krb5data, client) ||
               !krb5_kuserok(ssh_context, client, user)){
             log_msg("Kerberos tgt REFUSED for %.100s", user);
             debug("Kerberos tgt REFUSED for %.100s", user);
           }
           free(krb5data.data);
-#endif
+#else /* KRB5 */
+	  {
+	    /* Accept Kerberos tgt. */
+	    char *tgt = packet_get_string(NULL);
+	    if (!auth_kerberos_tgt(pw, tgt))
+	      debug("Kerberos tgt REFUSED for %s", user);
+	    xfree(tgt);
+	  }
+#endif /* KRB5 */
           continue;
-#endif /* KERBEROS_TGT_PASSING */
+#endif /* KRB5 || AFS */
           
-#ifdef KERBEROS
-#ifdef KRB5
+#ifdef AFS
+	case SSH_CMSG_HAVE_AFS_TOKEN:
+	  if (!k_hasafs() || !options.afs_token_passing) {
+	    packet_get_all();
+	    log_msg("AFS token passing disabled.");
+	    break;
+	  }
+	  else {
+	    /* Accept AFS token. */
+	    char *token_string = packet_get_string(NULL);
+	    if (!auth_afs_token(user, pw->pw_uid, token_string))
+	      debug("AFS token REFUSED for %s", user);
+	    xfree(token_string);
+	    continue;
+	  }
+#endif /* AFS */
+	  
+#if defined(KRB4) || defined(KRB5)
         case SSH_CMSG_AUTH_KERBEROS:
           if (!options.kerberos_authentication)
             {
@@ -2316,9 +2380,10 @@
               log_msg("Kerberos authentication disabled.");
               break;
             }
+#ifdef KRB5
           /* Try Kerberos authentication. */
           krb5data.data = packet_get_string((unsigned int *) &krb5data.length);
-          if (auth_kerberos(user, &krb5data, &tkt_client))
+          if (auth_krb5(user, &krb5data, &tkt_client))
             {
               char *tkt_user;
               
@@ -2347,11 +2412,31 @@
                 }
               free(tkt_user);
             }
-#endif /* KRB5 */
-          debug("Kerberos authentication failed for %.100s from %.200s",
-                user, get_canonical_hostname());
+#else /* !KRB5  XXX - how to make these coexist? */
+	  else {
+	    /* Try Kerberos v4 authentication. */
+	    KTEXT_ST auth;
+	    char *tkt_user = NULL;
+	    char *kdata = packet_get_string((unsigned int *)&auth.length);
+	    
+	    memcpy(auth.dat, kdata, auth.length);
+	    xfree(kdata);
+
+	    if (auth_krb4(user, &auth, &tkt_user)) {
+	      /* Client has successfully authenticated to us. */
+	      log_msg("Kerberos authentication accepted %s for account "
+		      "%.100s from %.200s", tkt_user, user,
+		      get_canonical_hostname());
+	      authentication_type = SSH_AUTH_KERBEROS;
+	      authenticated = 1;
+	      xfree(tkt_user);
           break;
-#endif /* KERBEROS */
+	    }
+	    log_msg("Kerberos authentication failed for account "
+		    "%.100s from %.200s", user, get_canonical_hostname());
+	  }
+#endif /* KRB5 */
+#endif /* KRB5 || KRB4 */
           
         case SSH_CMSG_AUTH_RHOSTS:
           if (!options.rhosts_authentication)
@@ -2568,7 +2653,7 @@
             if (!strncmp(buf, "challenge ", 10) ||
                 !strncmp(buf, "chalnecho ", 10)) {
               snprintf(prompt, sizeof(prompt),
-                       "Challenge \"%.100s\": ",&buf[10]);
+                       "%.100s",&buf[10]);
               debug("TIS challenge %.500s", buf);
               packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
               packet_put_string(prompt, strlen(prompt));
@@ -2657,11 +2742,11 @@
           password_attempts++;
 
           /* Try authentication with the password. */
-#if defined(KERBEROS) && defined(KRB5)
+#ifdef KRB5
           if (auth_password(user, password, client))
-#else  /* defined(KERBEROS) && defined(KRB5) */
+#else  /* KRB5 */
           if (auth_password(user, password))
-#endif /* defined(KERBEROS) && defined(KRB5) */
+#endif /* KRB5 */
             {
               /* Successful authentication. */
               /* Clear the password from memory. */
@@ -2688,7 +2773,7 @@
       if (authenticated)
         break;
 
-#ifdef KERBEROS
+#if defined(KRB5)
       /* If you forwarded a ticket you get one shot for proper
          authentication. */
       /* If tgt was passed unlink file */
@@ -2699,7 +2784,7 @@
           else
             ticket = NULL;
       }
-#endif /* KERBEROS */
+#endif /* KRB5 */
       
       /* Send a message indicating that the authentication attempt failed. */
       packet_start(SSH_SMSG_FAILURE);
@@ -2724,7 +2809,7 @@
                             get_canonical_hostname());
       }
 
-#if defined (__FreeBSD__) && defined (HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined (HAVE_LOGIN_CAP_H)
   
   lc = login_getclass(pw->pw_class);
   
@@ -2965,6 +3050,21 @@
           display = x11_create_display_inet(screen);
           if (!display)
             goto fail;
+#ifdef AFS
+	  /* Setup to have a local .Xauthority, if homedir is in AFS. */
+	  {
+	    struct stat st;
+	    char cell[64], *xauthdir = "/ticket";
+	    
+	    if (k_hasafs() && k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) {
+	      xauthfile = xmalloc(MAXPATHLEN);
+	      if (stat(xauthdir, &st) < 0)
+		xauthdir = "/tmp";
+          snprintf(xauthfile, MAXPATHLEN, "%s/Xauth%d_%d", xauthdir,
+                   pw->pw_uid, getpid());
+	    }
+	  }
+#endif /* AFS */
           break;
 #else /* XAUTH_PATH */
           /* No xauth program; we won't accept forwarding with spoofing. */
@@ -3283,12 +3383,9 @@
   struct sockaddr_in from;
   int fromlen;
   struct pty_cleanup_context cleanup_context;
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
   login_cap_t *lc;
 #endif
-#if defined (__bsdi__) && _BSDI_VERSION >= 199510 
-  struct timeval tp;
-#endif /*  __bsdi__ && _BSDI_VERSION >= 199510 */
 
   /* We no longer need the child running on user's privileges. */
   userfile_uninit();
@@ -3389,7 +3486,7 @@
       record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, 
                    &from);
 
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
       lc = login_getclass(pw->pw_class);
 #endif
 
@@ -3398,7 +3495,7 @@
       snprintf(line, sizeof(line), "%.200s/.hushlogin", pw->pw_dir);
       quiet_login = stat(line, &st) >= 0;
 
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
       quiet_login = login_getcapbool(lc, "hushlogin", quiet_login);
 #endif
      
@@ -3425,7 +3522,7 @@
         }
 #endif /* HAVE_SIA */
 
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__)  || defined(__NetBSD__)
       if (command == NULL && !quiet_login)
         {
 #ifdef HAVE_LOGIN_CAP_H
@@ -3457,7 +3554,7 @@
           FILE *f;
 
           /* Print /etc/motd if it exists. */
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
           f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", "/etc/motd"),
                     "r");
 #else
@@ -3469,33 +3566,9 @@
                 fputs(line, stdout);
               fclose(f);
             }
-#if defined (__bsdi__) && _BSDI_VERSION >= 199510
-          if (pw->pw_change || pw->pw_expire)
-            (void)gettimeofday(&tp, (struct timezone *)NULL);
-          if (pw->pw_change)
-            {
-              if (tp.tv_sec >= pw->pw_change)
-                {
-                  fprintf(stderr,"Sorry -- your password has expired.\n");
-                  exit(254);
-                }
-              days_before_password_expires = (pw->pw_change - tp.tv_sec) /
-                86400;
-            }
-          if (pw->pw_expire)
-            {
-              if (tp.tv_sec >= pw->pw_expire)
-                {
-                  fprintf(stderr,"Sorry -- your account has expired.\n");
-                  exit(254);
-                }
-              days_before_account_expires = (pw->pw_expire - tp.tv_sec) /
-                86400;
-            }
-#endif /* __bsdi__ & _BSDI_VERSION >= 199510   */
         }
 
-#if defined (__FreeBSD__) && defined HAVE_LOGIN_CAP_H
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined HAVE_LOGIN_CAP_H
       login_close(lc);
 #endif
 
@@ -3883,8 +3956,11 @@
   lc = login_getclass(pw->pw_class);
   auth_checknologin(lc);
 #else /* !HAVE_LOGIN_CAP_H */
-#if defined (__bsdi__) && _BSDI_VERSION > 199510
+#if ( defined (__bsdi__) && _BSDI_VERSION > 199510 ) || (defined(HAVE_LOGIN_CAP_H) && defined(__NetBSD__))
   login_cap_t *lc = 0;
+#if defined(__NetBSD__)
+  char *real_shell;
+#endif
   
   if ((lc = login_getclass(pw->pw_class)) == NULL)
     {
@@ -4019,7 +4095,7 @@
   if (command != NULL || !options.use_login)
 #endif /* USELOGIN */
     {
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
       char *p, *s, **tmpenv;
 
       /* Initialize the new environment.
@@ -4180,10 +4256,23 @@
      and means /bin/sh. */
   shell = (user_shell[0] == '\0') ? DEFAULT_SHELL : user_shell;
 
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
   real_shell = login_getcapstr(lc, "shell", (char*)shell, (char*)shell);
   login_close(lc);
 #endif /* HAVE_LOGIN_CAP_H */
+
+#ifdef AFS
+  /* Try to get AFS tokens for the local cell. */
+  if (k_hasafs()) {
+    char cell[64];
+    
+    if (k_afs_cell_of_file(user_dir, cell, sizeof(cell)) == 0)
+      krb_afslog(cell, 0);
+
+    krb_afslog(0, 0);
+  }
+#endif /* AFS */
+
   /* Initialize the environment if not already done. In the first part we
      allocate space for all environment variables. */
   if (env == NULL)
@@ -4290,13 +4379,21 @@
   }
 #endif
 
-#ifdef KERBEROS
-  /* Set KRBTKFILE to point to our ticket */
+  /* Set KRBTKFILE to point to our ticket. */
 #ifdef KRB5
   if (ticket)
     child_set_env(&env, &envsize, "KRB5CCNAME", ticket);
 #endif /* KRB5 */
-#endif /* KERBEROS */
+#ifdef KRB4 /* XXX - how to make these coexist? */
+  if (ticket)
+    child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+
+#ifdef AFS
+  /* Set XAUTHORITY to a local file, if homedir is in AFS. */
+  if (xauthfile)
+      child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
+#endif /* AFS */
+#endif /* KRB4 */
 
   /* Set variable for forwarded authentication connection, if we have one. */
   if (auth_get_socket_name() != NULL)
@@ -4554,7 +4651,7 @@
           /* Execute the shell. */
           argv[0] = buf;
           argv[1] = NULL;
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__)  || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
           execve(real_shell, argv, env);
 #else
           execve(shell, argv, env);
@@ -4579,7 +4676,7 @@
   argv[1] = "-c";
   argv[2] = (char *)command;
   argv[3] = NULL;
-#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
+#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H)
   execve(real_shell, argv, env);
 #else
   execve(shell, argv, env);
