Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
LSH
lsh
Commits
f010d5dc
Commit
f010d5dc
authored
Oct 30, 1998
by
Niels Möller
Browse files
Implemented the session service and spawning of a shell.
Rev: src/server.c:1.17 Rev: src/server.h:1.8
parent
93674f7f
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/server.c
View file @
f010d5dc
...
...
@@ -26,17 +26,26 @@
#include
"server.h"
#include
"abstract_io.h"
#include
"channel.h"
#include
"connection.h"
#include
"debug.h"
#include
"format.h"
#include
"keyexchange.h"
#include
"read_line.h"
#include
"read_packet.h"
#include
"ssh.h"
#include
"unpad.h"
#include
"version.h"
#include
"werror.h"
#include
"xalloc.h"
#include
<assert.h>
#include
<string.h>
#include
<errno.h>
#include
<sys/types.h>
#include
<sys/socket.h>
struct
server_callback
{
struct
fd_callback
super
;
...
...
@@ -205,3 +214,332 @@ struct close_callback *make_server_close_handler(void)
return
c
;
}
/* Session */
struct
server_session
{
struct
ssh_channel
super
;
UINT32
max_window
;
/* User information */
struct
unix_user
*
user
;
/* Non-zero if a shell or command has been started. */
int
running
;
};
struct
ssh_channel
*
make_server_session
(
struct
unix_user
*
user
,
UINT32
max_window
,
struct
alist
*
request_types
)
{
struct
server_session
*
self
;
NEW
(
self
);
init_channel
(
&
self
->
super
);
self
->
super
.
max_window
=
max_window
;
self
->
super
.
rec_window_size
=
max_window
;
/* FIXME: Make maximum packet size configurable. */
self
->
super
.
rec_max_packet
=
SSH_MAX_PACKET
;
self
->
super
.
request_types
=
request_types
;
self
->
user
=
user
;
self
->
running
=
0
;
return
&
self
->
super
;
}
struct
open_session
{
struct
channel_open
super
;
struct
unix_user
*
user
;
struct
alist
*
session_requests
;
};
#define WINDOW_SIZE (SSH_MAX_PACKET << 3)
static
struct
ssh_channel
*
do_open_session
(
struct
channel_open
*
c
,
struct
simple_buffer
*
args
,
UINT32
*
error
,
char
**
error_msg
,
struct
lsh_string
**
data
)
{
struct
open_session
*
closure
=
(
struct
open_session
*
)
c
;
MDEBUG
(
closure
);
debug
(
"server.c: do_open_session()
\n
"
);
if
(
!
parse_eod
(
args
))
return
0
;
return
make_server_session
(
closure
->
user
,
WINDOW_SIZE
,
closure
->
session_requests
);
}
struct
channel_open
*
make_open_session
(
struct
unix_user
*
user
,
struct
alist
*
session_requests
)
{
struct
open_session
*
closure
;
NEW
(
closure
);
closure
->
super
.
handler
=
do_open_session
;
closure
->
user
=
user
;
closure
->
session_requests
=
session_requests
;
return
&
closure
->
super
;
}
struct
server_connection_service
{
struct
unix_service
super
;
struct
alist
*
global_requests
;
/* Requests specific to session channels */
struct
alist
*
session_requests
;
/* FIXME: Doesn't support any channel types but "session".
* This must be fixed to support for "direct-tcpip" channels. */
};
/* Start an authenticated ssh-connection service */
static
struct
ssh_service
*
do_login
(
struct
unix_service
*
c
,
struct
unix_user
*
user
)
{
struct
server_connection_service
*
closure
=
(
struct
server_connection_service
*
)
c
;
MDEBUG
(
closure
);
debug
(
"server.c: do_login()
\n
"
);
return
make_connection_service
(
closure
->
global_requests
,
make_alist
(
1
,
ATOM_SESSION
,
make_open_session
(
user
,
closure
->
session_requests
),
-
1
),
NULL
);
}
struct
unix_service
*
make_server_session_service
(
struct
alist
*
global_requests
,
struct
alist
*
session_requests
)
{
struct
server_connection_service
*
closure
;
NEW
(
closure
);
closure
->
super
.
login
=
do_login
;
closure
->
global_requests
=
global_requests
;
closure
->
session_requests
=
session_requests
;
return
&
closure
->
super
;
}
struct
shell_request
{
struct
channel_request
super
;
struct
io_backend
*
backend
;
};
/* Creates a one-way socket connection. Returns 1 on successm 0 on
* failure. fds[0] is for reading, fds[1] for writing (like for the
* pipe() system call). */
static
int
make_pipe
(
int
*
fds
)
{
/* From the shutdown(2) man page */
#define REC 0
#define SEND 1
return
!
socketpair
(
AF_UNIX
,
SOCK_STREAM
,
0
,
fds
)
&&
!
shutdown
(
fds
[
0
],
SEND
)
&&
!
shutdown
(
fds
[
1
],
REC
);
}
static
char
*
make_env_pair
(
char
*
name
,
struct
lsh_string
*
value
)
{
return
ssh_format
(
"%z=%lS
\0
"
,
name
,
value
)
->
data
;
}
static
char
*
make_env_pair_c
(
char
*
name
,
char
*
value
)
{
return
ssh_format
(
"%z=%z
\0
"
,
name
,
value
)
->
data
;
}
static
int
do_spawn_shell
(
struct
channel_request
*
c
,
struct
ssh_channel
*
channel
,
int
want_reply
,
struct
simple_buffer
*
args
)
{
struct
shell_request
*
closure
=
(
struct
shell_request
*
)
c
;
struct
server_session
*
session
=
(
struct
server_session
*
)
channel
;
int
in_fds
[
2
];
int
out_fds
[
2
];
int
err_fds
[
2
];
MDEBUG
(
closure
);
MDEBUG
(
channel
);
if
(
!
parse_eod
(
args
))
return
LSH_FAIL
|
LSH_DIE
;
if
(
session
->
running
)
/* Already spawned a shell or command */
goto
fail
;
/* {in_fds|out_fds|err_fds}[0] is for reading,
* {in_fds|out_fds|err_fds}[1] for writing. */
if
(
make_pipe
(
in_fds
))
{
if
(
make_pipe
(
out_fds
))
{
if
(
make_pipe
(
err_fds
))
{
pid_t
child
;
switch
(
child
=
fork
())
{
case
-
1
:
werror
(
"fork() failed: %s
\n
"
,
strerror
(
errno
));
/* Close and return channel_failure */
break
;
case
0
:
/* Child */
if
(
!
session
->
user
->
shell
)
{
werror
(
"No login shell!
\n
"
);
exit
(
EXIT_FAILURE
);
}
if
(
getuid
()
!=
session
->
user
->
uid
)
if
(
!
change_uid
(
session
->
user
))
{
werror
(
"Changing uid failed!
\n
"
);
exit
(
EXIT_FAILURE
);
}
assert
(
getuid
()
==
session
->
user
->
uid
);
if
(
!
change_dir
(
session
->
user
))
{
werror
(
"Could not change to home (or root) directory!
\n
"
);
exit
(
EXIT_FAILURE
);
}
/* Close all descriptors but those used for
* communicationg with parent. We rely on the
* close-on-exec flag for all fd:s handled by the
* backend. */
close
(
STDIN_FILENO
);
if
(
dup2
(
in_fds
[
0
],
STDIN_FILENO
)
<
0
)
{
werror
(
"Can't dup stdin!
\n
"
);
exit
(
EXIT_FAILURE
);
}
close
(
in_fds
[
0
]);
close
(
in_fds
[
1
]);
close
(
STDOUT_FILENO
);
if
(
dup2
(
out_fds
[
1
],
STDOUT_FILENO
)
<
0
)
{
werror
(
"Can't dup stdout!
\n
"
);
exit
(
EXIT_FAILURE
);
}
close
(
out_fds
[
0
]);
close
(
out_fds
[
1
]);
close
(
STDERR_FILENO
);
if
(
dup2
(
err_fds
[
1
],
STDERR_FILENO
)
<
0
)
{
/* Can't write any message to stderr. */
exit
(
EXIT_FAILURE
);
}
close
(
err_fds
[
0
]);
close
(
err_fds
[
1
]);
{
char
*
shell
=
session
->
user
->
shell
->
data
;
#define MAX_ENV 7
char
*
env
[
MAX_ENV
];
char
*
tz
=
getenv
(
"TZ"
);
int
i
=
0
;
env
[
i
++
]
=
make_env_pair
(
"LOGNAME"
,
session
->
user
->
name
);
env
[
i
++
]
=
make_env_pair
(
"USER"
,
session
->
user
->
name
);
env
[
i
++
]
=
make_env_pair
(
"SHELL"
,
session
->
user
->
shell
);
if
(
session
->
user
->
home
)
env
[
i
++
]
=
make_env_pair
(
"HOME"
,
session
->
user
->
home
);
if
(
tz
)
env
[
i
++
]
=
make_env_pair_c
(
"TZ"
,
tz
);
/* FIXME: The value of $PATH should not be hard-coded */
env
[
i
++
]
=
"PATH=/bin:/usr/bin"
;
env
[
i
++
]
=
NULL
;
assert
(
i
<=
MAX_ENV
);
if
(
execle
(
shell
,
shell
,
NULL
,
env
)
<
0
)
exit
(
EXIT_FAILURE
);
#undef MAX_ENV
}
default:
/* Parent */
/* FIXME: Install a calback to catch dying children */
/* Close the child's fd:s */
close
(
in_fds
[
0
]);
close
(
out_fds
[
1
]);
close
(
err_fds
[
2
]);
io_write
(
closure
->
backend
,
in_fds
[
1
],
SSH_MAX_PACKET
,
/* FIXME: Use a proper close callback */
NULL
);
io_read
(
closure
->
backend
,
out_fds
[
0
],
make_channel_read_data
(
channel
),
NULL
);
io_read
(
closure
->
backend
,
err_fds
[
0
],
make_channel_read_stderr
(
channel
),
NULL
);
session
->
running
=
1
;
return
want_reply
?
A_WRITE
(
channel
->
write
,
format_channel_success
(
channel
->
channel_number
))
:
LSH_OK
|
LSH_GOON
;
}
close
(
err_fds
[
0
]);
close
(
err_fds
[
1
]);
}
close
(
out_fds
[
0
]);
close
(
out_fds
[
1
]);
}
close
(
in_fds
[
0
]);
close
(
in_fds
[
1
]);
}
fail:
return
want_reply
?
A_WRITE
(
channel
->
write
,
format_channel_failure
(
channel
->
channel_number
))
:
LSH_OK
|
LSH_GOON
;
}
struct
channel_request
*
make_shell_handler
(
struct
io_backend
*
backend
)
{
struct
shell_request
*
closure
;
NEW
(
closure
);
closure
->
super
.
handler
=
do_spawn_shell
;
return
&
closure
->
super
;
}
src/server.h
View file @
f010d5dc
...
...
@@ -26,10 +26,9 @@
#ifndef LSH_SERVER_H_INCLUDED
#define LSH_SERVER_H_INCLUDED
#include
"server.h"
#include
"io.h"
#include
"keyexchange.h"
#include
"password.h"
struct
fd_callback
*
make_server_callback
(
struct
io_backend
*
b
,
...
...
@@ -42,4 +41,16 @@ make_server_callback(struct io_backend *b,
struct
read_handler
*
make_server_read_line
(
struct
ssh_connection
*
c
);
struct
close_callback
*
make_server_close_handler
(
void
);
struct
ssh_channel
*
make_server_session
(
struct
unix_user
*
user
,
UINT32
max_window
,
struct
alist
*
request_types
);
struct
unix_service
*
make_server_session_service
(
struct
alist
*
global_requests
,
struct
alist
*
session_requests
);
struct
channel_open
*
make_open_session
(
struct
unix_user
*
user
,
struct
alist
*
session_requests
);
struct
channel_request
*
make_shell_handler
(
struct
io_backend
*
backend
);
#endif
/* LSH_SERVER_H_INCLUDED */
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment