diff options
Diffstat (limited to 'session.c')
-rw-r--r-- | session.c | 463 |
1 files changed, 247 insertions, 216 deletions
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include "includes.h" | 35 | #include "includes.h" |
36 | RCSID("$OpenBSD: session.c,v 1.126 2002/02/14 23:28:00 markus Exp $"); | 36 | RCSID("$OpenBSD: session.c,v 1.127 2002/02/15 23:11:26 markus Exp $"); |
37 | 37 | ||
38 | #include "ssh.h" | 38 | #include "ssh.h" |
39 | #include "ssh1.h" | 39 | #include "ssh1.h" |
@@ -657,6 +657,7 @@ do_exec(Session *s, const char *command) | |||
657 | original_command = NULL; | 657 | original_command = NULL; |
658 | } | 658 | } |
659 | 659 | ||
660 | |||
660 | /* administrative, login(1)-like work */ | 661 | /* administrative, login(1)-like work */ |
661 | void | 662 | void |
662 | do_login(Session *s, const char *command) | 663 | do_login(Session *s, const char *command) |
@@ -677,7 +678,7 @@ do_login(Session *s, const char *command) | |||
677 | if (packet_connection_is_on_socket()) { | 678 | if (packet_connection_is_on_socket()) { |
678 | fromlen = sizeof(from); | 679 | fromlen = sizeof(from); |
679 | if (getpeername(packet_get_connection_in(), | 680 | if (getpeername(packet_get_connection_in(), |
680 | (struct sockaddr *) & from, &fromlen) < 0) { | 681 | (struct sockaddr *) & from, &fromlen) < 0) { |
681 | debug("getpeername: %.100s", strerror(errno)); | 682 | debug("getpeername: %.100s", strerror(errno)); |
682 | fatal_cleanup(); | 683 | fatal_cleanup(); |
683 | } | 684 | } |
@@ -883,134 +884,13 @@ void copy_environment(char **source, char ***env, u_int *envsize) | |||
883 | } | 884 | } |
884 | } | 885 | } |
885 | 886 | ||
886 | /* | 887 | static char ** |
887 | * Performs common processing for the child, such as setting up the | 888 | do_setup_env(Session *s, const char *shell) |
888 | * environment, closing extra file descriptors, setting the user and group | ||
889 | * ids, and executing the command or shell. | ||
890 | */ | ||
891 | void | ||
892 | do_child(Session *s, const char *command) | ||
893 | { | 889 | { |
894 | const char *shell, *hostname = NULL, *cp = NULL; | ||
895 | struct passwd *pw = s->pw; | ||
896 | char buf[256]; | 890 | char buf[256]; |
897 | char cmd[1024]; | 891 | u_int i, envsize; |
898 | FILE *f = NULL; | ||
899 | u_int envsize, i; | ||
900 | char **env; | 892 | char **env; |
901 | extern char **environ; | 893 | struct passwd *pw = s->pw; |
902 | struct stat st; | ||
903 | char *argv[10]; | ||
904 | int do_xauth; | ||
905 | |||
906 | do_xauth = | ||
907 | s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; | ||
908 | |||
909 | /* remove hostkey from the child's memory */ | ||
910 | destroy_sensitive_data(); | ||
911 | |||
912 | /* login(1) is only called if we execute the login shell */ | ||
913 | if (options.use_login && command != NULL) | ||
914 | options.use_login = 0; | ||
915 | |||
916 | #if !defined(HAVE_OSF_SIA) | ||
917 | if (!options.use_login) { | ||
918 | # ifdef HAVE_LOGIN_CAP | ||
919 | if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) | ||
920 | f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, | ||
921 | _PATH_NOLOGIN), "r"); | ||
922 | # else /* HAVE_LOGIN_CAP */ | ||
923 | if (pw->pw_uid) | ||
924 | f = fopen(_PATH_NOLOGIN, "r"); | ||
925 | # endif /* HAVE_LOGIN_CAP */ | ||
926 | if (f) { | ||
927 | /* /etc/nologin exists. Print its contents and exit. */ | ||
928 | while (fgets(buf, sizeof(buf), f)) | ||
929 | fputs(buf, stderr); | ||
930 | fclose(f); | ||
931 | exit(254); | ||
932 | } | ||
933 | } | ||
934 | #endif /* HAVE_OSF_SIA */ | ||
935 | |||
936 | /* Set login name, uid, gid, and groups. */ | ||
937 | /* Login(1) does this as well, and it needs uid 0 for the "-h" | ||
938 | switch, so we let login(1) to this for us. */ | ||
939 | if (!options.use_login) { | ||
940 | #ifdef HAVE_OSF_SIA | ||
941 | session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty); | ||
942 | if (!check_quietlogin(s, command)) | ||
943 | do_motd(); | ||
944 | #else /* HAVE_OSF_SIA */ | ||
945 | #ifdef HAVE_CYGWIN | ||
946 | if (is_winnt) { | ||
947 | #else | ||
948 | if (getuid() == 0 || geteuid() == 0) { | ||
949 | #endif | ||
950 | # ifdef HAVE_GETUSERATTR | ||
951 | set_limits_from_userattr(pw->pw_name); | ||
952 | # endif /* HAVE_GETUSERATTR */ | ||
953 | # ifdef HAVE_LOGIN_CAP | ||
954 | if (setusercontext(lc, pw, pw->pw_uid, | ||
955 | (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { | ||
956 | perror("unable to set user context"); | ||
957 | exit(1); | ||
958 | } | ||
959 | # else /* HAVE_LOGIN_CAP */ | ||
960 | #if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) | ||
961 | /* Sets login uid for accounting */ | ||
962 | if (getluid() == -1 && setluid(pw->pw_uid) == -1) | ||
963 | error("setluid: %s", strerror(errno)); | ||
964 | #endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ | ||
965 | |||
966 | if (setlogin(pw->pw_name) < 0) | ||
967 | error("setlogin failed: %s", strerror(errno)); | ||
968 | if (setgid(pw->pw_gid) < 0) { | ||
969 | perror("setgid"); | ||
970 | exit(1); | ||
971 | } | ||
972 | /* Initialize the group list. */ | ||
973 | if (initgroups(pw->pw_name, pw->pw_gid) < 0) { | ||
974 | perror("initgroups"); | ||
975 | exit(1); | ||
976 | } | ||
977 | endgrent(); | ||
978 | # ifdef USE_PAM | ||
979 | /* | ||
980 | * PAM credentials may take the form of | ||
981 | * supplementary groups. These will have been | ||
982 | * wiped by the above initgroups() call. | ||
983 | * Reestablish them here. | ||
984 | */ | ||
985 | do_pam_setcred(0); | ||
986 | # endif /* USE_PAM */ | ||
987 | # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) | ||
988 | irix_setusercontext(pw); | ||
989 | # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ | ||
990 | #ifdef _AIX | ||
991 | aix_usrinfo(s) | ||
992 | #endif | ||
993 | |||
994 | /* Permanently switch to the desired uid. */ | ||
995 | permanently_set_uid(pw); | ||
996 | # endif /* HAVE_LOGIN_CAP */ | ||
997 | } | ||
998 | #endif /* HAVE_OSF_SIA */ | ||
999 | |||
1000 | #ifdef HAVE_CYGWIN | ||
1001 | if (is_winnt) | ||
1002 | #endif | ||
1003 | if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) | ||
1004 | fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); | ||
1005 | } | ||
1006 | /* | ||
1007 | * Get the shell from the password data. An empty shell field is | ||
1008 | * legal, and means /bin/sh. | ||
1009 | */ | ||
1010 | shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; | ||
1011 | #ifdef HAVE_LOGIN_CAP | ||
1012 | shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); | ||
1013 | #endif | ||
1014 | 894 | ||
1015 | /* Initialize the environment. */ | 895 | /* Initialize the environment. */ |
1016 | envsize = 100; | 896 | envsize = 100; |
@@ -1060,7 +940,7 @@ do_child(Session *s, const char *command) | |||
1060 | while (custom_environment) { | 940 | while (custom_environment) { |
1061 | struct envstring *ce = custom_environment; | 941 | struct envstring *ce = custom_environment; |
1062 | char *s = ce->s; | 942 | char *s = ce->s; |
1063 | int i; | 943 | |
1064 | for (i = 0; s[i] != '=' && s[i]; i++) | 944 | for (i = 0; s[i] != '=' && s[i]; i++) |
1065 | ; | 945 | ; |
1066 | if (s[i] == '=') { | 946 | if (s[i] == '=') { |
@@ -1074,7 +954,7 @@ do_child(Session *s, const char *command) | |||
1074 | } | 954 | } |
1075 | 955 | ||
1076 | snprintf(buf, sizeof buf, "%.50s %d %d", | 956 | snprintf(buf, sizeof buf, "%.50s %d %d", |
1077 | get_remote_ipaddr(), get_remote_port(), get_local_port()); | 957 | get_remote_ipaddr(), get_remote_port(), get_local_port()); |
1078 | child_set_env(&env, &envsize, "SSH_CLIENT", buf); | 958 | child_set_env(&env, &envsize, "SSH_CLIENT", buf); |
1079 | 959 | ||
1080 | if (s->ttyfd != -1) | 960 | if (s->ttyfd != -1) |
@@ -1125,6 +1005,206 @@ do_child(Session *s, const char *command) | |||
1125 | for (i = 0; env[i]; i++) | 1005 | for (i = 0; env[i]; i++) |
1126 | fprintf(stderr, " %.200s\n", env[i]); | 1006 | fprintf(stderr, " %.200s\n", env[i]); |
1127 | } | 1007 | } |
1008 | return env; | ||
1009 | } | ||
1010 | |||
1011 | /* | ||
1012 | * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found | ||
1013 | * first in this order). | ||
1014 | */ | ||
1015 | static void | ||
1016 | do_rc_files(Session *s, const char *shell) | ||
1017 | { | ||
1018 | FILE *f = NULL; | ||
1019 | char cmd[1024]; | ||
1020 | int do_xauth; | ||
1021 | struct stat st; | ||
1022 | |||
1023 | do_xauth = | ||
1024 | s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; | ||
1025 | |||
1026 | /* ignore _PATH_SSH_USER_RC for subsystems */ | ||
1027 | if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { | ||
1028 | snprintf(cmd, sizeof cmd, "%s -c '%s %s'", | ||
1029 | shell, _PATH_BSHELL, _PATH_SSH_USER_RC); | ||
1030 | if (debug_flag) | ||
1031 | fprintf(stderr, "Running %s\n", cmd); | ||
1032 | f = popen(cmd, "w"); | ||
1033 | if (f) { | ||
1034 | if (do_xauth) | ||
1035 | fprintf(f, "%s %s\n", s->auth_proto, | ||
1036 | s->auth_data); | ||
1037 | pclose(f); | ||
1038 | } else | ||
1039 | fprintf(stderr, "Could not run %s\n", | ||
1040 | _PATH_SSH_USER_RC); | ||
1041 | } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { | ||
1042 | if (debug_flag) | ||
1043 | fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, | ||
1044 | _PATH_SSH_SYSTEM_RC); | ||
1045 | f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); | ||
1046 | if (f) { | ||
1047 | if (do_xauth) | ||
1048 | fprintf(f, "%s %s\n", s->auth_proto, | ||
1049 | s->auth_data); | ||
1050 | pclose(f); | ||
1051 | } else | ||
1052 | fprintf(stderr, "Could not run %s\n", | ||
1053 | _PATH_SSH_SYSTEM_RC); | ||
1054 | } else if (do_xauth && options.xauth_location != NULL) { | ||
1055 | /* Add authority data to .Xauthority if appropriate. */ | ||
1056 | if (debug_flag) { | ||
1057 | fprintf(stderr, | ||
1058 | "Running %.100s add " | ||
1059 | "%.100s %.100s %.100s\n", | ||
1060 | options.xauth_location, s->auth_display, | ||
1061 | s->auth_proto, s->auth_data); | ||
1062 | } | ||
1063 | snprintf(cmd, sizeof cmd, "%s -q -", | ||
1064 | options.xauth_location); | ||
1065 | f = popen(cmd, "w"); | ||
1066 | if (f) { | ||
1067 | fprintf(f, "add %s %s %s\n", | ||
1068 | s->auth_display, s->auth_proto, | ||
1069 | s->auth_data); | ||
1070 | pclose(f); | ||
1071 | } else { | ||
1072 | fprintf(stderr, "Could not run %s\n", | ||
1073 | cmd); | ||
1074 | } | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | static void | ||
1079 | do_nologin(struct passwd *pw) | ||
1080 | { | ||
1081 | FILE *f = NULL; | ||
1082 | char buf[1024]; | ||
1083 | |||
1084 | #ifdef HAVE_LOGIN_CAP | ||
1085 | if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) | ||
1086 | f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, | ||
1087 | _PATH_NOLOGIN), "r"); | ||
1088 | #else | ||
1089 | if (pw->pw_uid) | ||
1090 | f = fopen(_PATH_NOLOGIN, "r"); | ||
1091 | #endif | ||
1092 | if (f) { | ||
1093 | /* /etc/nologin exists. Print its contents and exit. */ | ||
1094 | while (fgets(buf, sizeof(buf), f)) | ||
1095 | fputs(buf, stderr); | ||
1096 | fclose(f); | ||
1097 | exit(254); | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | /* Set login name, uid, gid, and groups. */ | ||
1102 | static void | ||
1103 | do_setusercontext(struct passwd *pw) | ||
1104 | { | ||
1105 | #ifdef HAVE_CYGWIN | ||
1106 | if (iswinnt) { | ||
1107 | #else /* HAVE_CYGWIN */ | ||
1108 | if (getuid() == 0 || geteuid() == 0) { | ||
1109 | #endif /* HAVE_CYGWIN */ | ||
1110 | #ifdef HAVE_GETUSERATTR | ||
1111 | set_limits_from_userattr(pw->pw_name); | ||
1112 | #endif /* HAVE_GETUSERATTR */ | ||
1113 | #ifdef HAVE_LOGIN_CAP | ||
1114 | if (setusercontext(lc, pw, pw->pw_uid, | ||
1115 | (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { | ||
1116 | perror("unable to set user context"); | ||
1117 | exit(1); | ||
1118 | } | ||
1119 | #else | ||
1120 | # if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) | ||
1121 | /* Sets login uid for accounting */ | ||
1122 | if (getluid() == -1 && setluid(pw->pw_uid) == -1) | ||
1123 | error("setluid: %s", strerror(errno)); | ||
1124 | # endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ | ||
1125 | |||
1126 | if (setlogin(pw->pw_name) < 0) | ||
1127 | error("setlogin failed: %s", strerror(errno)); | ||
1128 | if (setgid(pw->pw_gid) < 0) { | ||
1129 | perror("setgid"); | ||
1130 | exit(1); | ||
1131 | } | ||
1132 | /* Initialize the group list. */ | ||
1133 | if (initgroups(pw->pw_name, pw->pw_gid) < 0) { | ||
1134 | perror("initgroups"); | ||
1135 | exit(1); | ||
1136 | } | ||
1137 | endgrent(); | ||
1138 | # ifdef USE_PAM | ||
1139 | /* | ||
1140 | * PAM credentials may take the form of supplementary groups. | ||
1141 | * These will have been wiped by the above initgroups() call. | ||
1142 | * Reestablish them here. | ||
1143 | */ | ||
1144 | do_pam_setcred(0); | ||
1145 | # endif /* USE_PAM */ | ||
1146 | # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) | ||
1147 | irix_setusercontext(pw); | ||
1148 | # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ | ||
1149 | #ifdef _AIX | ||
1150 | aix_usrinfo(s) | ||
1151 | #endif | ||
1152 | /* Permanently switch to the desired uid. */ | ||
1153 | permanently_set_uid(pw); | ||
1154 | #endif | ||
1155 | } | ||
1156 | if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) | ||
1157 | fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); | ||
1158 | } | ||
1159 | |||
1160 | /* | ||
1161 | * Performs common processing for the child, such as setting up the | ||
1162 | * environment, closing extra file descriptors, setting the user and group | ||
1163 | * ids, and executing the command or shell. | ||
1164 | */ | ||
1165 | void | ||
1166 | do_child(Session *s, const char *command) | ||
1167 | { | ||
1168 | extern char **environ; | ||
1169 | char **env; | ||
1170 | char *argv[10]; | ||
1171 | const char *shell, *shell0, *hostname = NULL; | ||
1172 | struct passwd *pw = s->pw; | ||
1173 | u_int i; | ||
1174 | |||
1175 | /* remove hostkey from the child's memory */ | ||
1176 | destroy_sensitive_data(); | ||
1177 | |||
1178 | /* login(1) is only called if we execute the login shell */ | ||
1179 | if (options.use_login && command != NULL) | ||
1180 | options.use_login = 0; | ||
1181 | |||
1182 | /* | ||
1183 | * Login(1) does this as well, and it needs uid 0 for the "-h" | ||
1184 | * switch, so we let login(1) to this for us. | ||
1185 | */ | ||
1186 | if (!options.use_login) { | ||
1187 | #ifdef HAVE_OSF_SIA | ||
1188 | session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty); | ||
1189 | if (!check_quietlogin(s, command)) | ||
1190 | do_motd(); | ||
1191 | #else /* HAVE_OSF_SIA */ | ||
1192 | do_nologin(pw); | ||
1193 | do_setusercontext(pw); | ||
1194 | #endif /* HAVE_OSF_SIA */ | ||
1195 | } | ||
1196 | |||
1197 | /* | ||
1198 | * Get the shell from the password data. An empty shell field is | ||
1199 | * legal, and means /bin/sh. | ||
1200 | */ | ||
1201 | shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; | ||
1202 | #ifdef HAVE_LOGIN_CAP | ||
1203 | shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); | ||
1204 | #endif | ||
1205 | |||
1206 | env = do_setup_env(s, shell); | ||
1207 | |||
1128 | /* we have to stash the hostname before we close our socket. */ | 1208 | /* we have to stash the hostname before we close our socket. */ |
1129 | if (options.use_login) | 1209 | if (options.use_login) |
1130 | hostname = get_remote_name_or_ip(utmp_len, | 1210 | hostname = get_remote_name_or_ip(utmp_len, |
@@ -1192,114 +1272,65 @@ do_child(Session *s, const char *command) | |||
1192 | #endif | 1272 | #endif |
1193 | } | 1273 | } |
1194 | 1274 | ||
1195 | /* | 1275 | if (!options.use_login) |
1196 | * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found | 1276 | do_rc_files(s, shell); |
1197 | * first in this order). | ||
1198 | */ | ||
1199 | if (!options.use_login) { | ||
1200 | /* ignore _PATH_SSH_USER_RC for subsystems */ | ||
1201 | if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { | ||
1202 | snprintf(cmd, sizeof cmd, "%s -c '%s %s'", | ||
1203 | shell, _PATH_BSHELL, _PATH_SSH_USER_RC); | ||
1204 | if (debug_flag) | ||
1205 | fprintf(stderr, "Running %s\n", cmd); | ||
1206 | f = popen(cmd, "w"); | ||
1207 | if (f) { | ||
1208 | if (do_xauth) | ||
1209 | fprintf(f, "%s %s\n", s->auth_proto, | ||
1210 | s->auth_data); | ||
1211 | pclose(f); | ||
1212 | } else | ||
1213 | fprintf(stderr, "Could not run %s\n", | ||
1214 | _PATH_SSH_USER_RC); | ||
1215 | } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { | ||
1216 | if (debug_flag) | ||
1217 | fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, | ||
1218 | _PATH_SSH_SYSTEM_RC); | ||
1219 | f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); | ||
1220 | if (f) { | ||
1221 | if (do_xauth) | ||
1222 | fprintf(f, "%s %s\n", s->auth_proto, | ||
1223 | s->auth_data); | ||
1224 | pclose(f); | ||
1225 | } else | ||
1226 | fprintf(stderr, "Could not run %s\n", | ||
1227 | _PATH_SSH_SYSTEM_RC); | ||
1228 | } else if (do_xauth && options.xauth_location != NULL) { | ||
1229 | /* Add authority data to .Xauthority if appropriate. */ | ||
1230 | if (debug_flag) { | ||
1231 | fprintf(stderr, | ||
1232 | "Running %.100s add " | ||
1233 | "%.100s %.100s %.100s\n", | ||
1234 | options.xauth_location, s->auth_display, | ||
1235 | s->auth_proto, s->auth_data); | ||
1236 | } | ||
1237 | snprintf(cmd, sizeof cmd, "%s -q -", | ||
1238 | options.xauth_location); | ||
1239 | f = popen(cmd, "w"); | ||
1240 | if (f) { | ||
1241 | fprintf(f, "add %s %s %s\n", | ||
1242 | s->auth_display, s->auth_proto, | ||
1243 | s->auth_data); | ||
1244 | pclose(f); | ||
1245 | } else { | ||
1246 | fprintf(stderr, "Could not run %s\n", | ||
1247 | cmd); | ||
1248 | } | ||
1249 | } | ||
1250 | /* Get the last component of the shell name. */ | ||
1251 | cp = strrchr(shell, '/'); | ||
1252 | if (cp) | ||
1253 | cp++; | ||
1254 | else | ||
1255 | cp = shell; | ||
1256 | } | ||
1257 | 1277 | ||
1258 | /* restore SIGPIPE for child */ | 1278 | /* restore SIGPIPE for child */ |
1259 | signal(SIGPIPE, SIG_DFL); | 1279 | signal(SIGPIPE, SIG_DFL); |
1260 | 1280 | ||
1281 | if (options.use_login) { | ||
1282 | /* Launch login(1). */ | ||
1283 | |||
1284 | execl(LOGIN_PROGRAM, "login", "-h", hostname, | ||
1285 | #ifdef LOGIN_NEEDS_TERM | ||
1286 | (s->term ? s->term : "unknown"), | ||
1287 | #endif /* LOGIN_NEEDS_TERM */ | ||
1288 | "-p", "-f", "--", pw->pw_name, (char *)NULL); | ||
1289 | |||
1290 | /* Login couldn't be executed, die. */ | ||
1291 | |||
1292 | perror("login"); | ||
1293 | exit(1); | ||
1294 | } | ||
1295 | |||
1296 | /* Get the last component of the shell name. */ | ||
1297 | if ((shell0 = strrchr(shell, '/')) != NULL) | ||
1298 | shell0++; | ||
1299 | else | ||
1300 | shell0 = shell; | ||
1301 | |||
1261 | /* | 1302 | /* |
1262 | * If we have no command, execute the shell. In this case, the shell | 1303 | * If we have no command, execute the shell. In this case, the shell |
1263 | * name to be passed in argv[0] is preceded by '-' to indicate that | 1304 | * name to be passed in argv[0] is preceded by '-' to indicate that |
1264 | * this is a login shell. | 1305 | * this is a login shell. |
1265 | */ | 1306 | */ |
1266 | if (!command) { | 1307 | if (!command) { |
1267 | if (!options.use_login) { | 1308 | char argv0[256]; |
1268 | char buf[256]; | ||
1269 | 1309 | ||
1270 | /* Start the shell. Set initial character to '-'. */ | 1310 | /* Start the shell. Set initial character to '-'. */ |
1271 | buf[0] = '-'; | 1311 | argv0[0] = '-'; |
1272 | strlcpy(buf + 1, cp, sizeof(buf) - 1); | ||
1273 | 1312 | ||
1274 | /* Execute the shell. */ | 1313 | if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) |
1275 | argv[0] = buf; | 1314 | >= sizeof(argv0) - 1) { |
1276 | argv[1] = NULL; | 1315 | errno = EINVAL; |
1277 | execve(shell, argv, env); | ||
1278 | |||
1279 | /* Executing the shell failed. */ | ||
1280 | perror(shell); | 1316 | perror(shell); |
1281 | exit(1); | 1317 | exit(1); |
1318 | } | ||
1282 | 1319 | ||
1283 | } else { | 1320 | /* Execute the shell. */ |
1284 | /* Launch login(1). */ | 1321 | argv[0] = argv0; |
1285 | 1322 | argv[1] = NULL; | |
1286 | execl(LOGIN_PROGRAM, "login", "-h", hostname, | 1323 | execve(shell, argv, env); |
1287 | #ifdef LOGIN_NEEDS_TERM | ||
1288 | s->term? s->term : "unknown", | ||
1289 | #endif | ||
1290 | "-p", "-f", "--", pw->pw_name, (char *)NULL); | ||
1291 | |||
1292 | /* Login couldn't be executed, die. */ | ||
1293 | 1324 | ||
1294 | perror("login"); | 1325 | /* Executing the shell failed. */ |
1295 | exit(1); | 1326 | perror(shell); |
1296 | } | 1327 | exit(1); |
1297 | } | 1328 | } |
1298 | /* | 1329 | /* |
1299 | * Execute the command using the user's shell. This uses the -c | 1330 | * Execute the command using the user's shell. This uses the -c |
1300 | * option to execute the command. | 1331 | * option to execute the command. |
1301 | */ | 1332 | */ |
1302 | argv[0] = (char *) cp; | 1333 | argv[0] = (char *) shell0; |
1303 | argv[1] = "-c"; | 1334 | argv[1] = "-c"; |
1304 | argv[2] = (char *) command; | 1335 | argv[2] = (char *) command; |
1305 | argv[3] = NULL; | 1336 | argv[3] = NULL; |