Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
LSH
lsh
Commits
f010d5dc
Commit
f010d5dc
authored
Oct 30, 1998
by
Niels Möller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
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
Showing
2 changed files
with
351 additions
and
2 deletions
+351
-2
src/server.c
src/server.c
+338
-0
src/server.h
src/server.h
+13
-2
No files found.
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
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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