~ubuntu-branches/ubuntu/precise/libssh/precise

« back to all changes in this revision

Viewing changes to src/channels1.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-06-15 15:48:07 UTC
  • mfrom: (1.1.10 upstream) (4.1.12 sid)
  • Revision ID: james.westby@ubuntu.com-20110615154807-3muklcqfftr1vtch
Tags: 0.5.0-2
* debian/patches/0002-Check-for-NULL-pointers-in-string-c.patch:
  Consolidate patch (Should fix previous REJECT)
* Support multiarch spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * channels1.c - Support for SSH-1 type channels
 
3
 *
 
4
 * This file is part of the SSH Library
 
5
 *
 
6
 * Copyright (c) 2003-2008 by Aris Adamantiadis
 
7
 * Copyright (c) 2009      by Andreas Schneider <mail@cynapses.org>
 
8
 *
 
9
 * The SSH Library is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU Lesser General Public License as published by
 
11
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 
12
 * option) any later version.
 
13
 *
 
14
 * The SSH Library is distributed in the hope that it will be useful, but
 
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
17
 * License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Lesser General Public License
 
20
 * along with the SSH Library; see the file COPYING.  If not, write to
 
21
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
22
 * MA 02111-1307, USA.
 
23
 */
 
24
 
 
25
#include <string.h>
 
26
#include <stdlib.h>
 
27
#include <stdio.h>
 
28
#ifndef _WIN32
 
29
#include <arpa/inet.h>
 
30
#include <unistd.h>
 
31
#endif
 
32
 
 
33
#include "libssh/priv.h"
 
34
#include "libssh/ssh1.h"
 
35
#include "libssh/buffer.h"
 
36
#include "libssh/packet.h"
 
37
#include "libssh/channels.h"
 
38
#include "libssh/session.h"
 
39
 
 
40
#ifdef WITH_SSH1
 
41
 
 
42
/*
 
43
 * This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
 
44
 * The whole packets concerning shells are sent outside of a channel.
 
45
 * Thus, an inside limitation of this behavior is that you can't only
 
46
 * request one shell.
 
47
 * The question is still how they managed to embed two "channel" into one
 
48
 * protocol.
 
49
 */
 
50
 
 
51
int channel_open_session1(ssh_channel chan) {
 
52
  /*
 
53
   * We guess we are requesting an *exec* channel. It can only have one exec
 
54
   * channel. So we abort with an error if we need more than one.
 
55
   */
 
56
  ssh_session session = chan->session;
 
57
  if (session->exec_channel_opened) {
 
58
    ssh_set_error(session, SSH_REQUEST_DENIED,
 
59
        "SSH1 supports only one execution channel. "
 
60
        "One has already been opened");
 
61
    return -1;
 
62
  }
 
63
  session->exec_channel_opened = 1;
 
64
  chan->state = SSH_CHANNEL_STATE_OPEN;
 
65
  chan->local_maxpacket = 32000;
 
66
  chan->local_window = 64000;
 
67
  ssh_log(session, SSH_LOG_PACKET, "Opened a SSH1 channel session");
 
68
 
 
69
  return 0;
 
70
}
 
71
 
 
72
/*  10 SSH_CMSG_REQUEST_PTY
 
73
 *
 
74
 *  string       TERM environment variable value (e.g. vt100)
 
75
 *  32-bit int   terminal height, rows (e.g., 24)
 
76
 *  32-bit int   terminal width, columns (e.g., 80)
 
77
 *  32-bit int   terminal width, pixels (0 if no graphics) (e.g., 480)
 
78
 *  32-bit int   terminal height, pixels (0 if no graphics) (e.g., 640)
 
79
 *  n bytes      tty modes encoded in binary
 
80
 *  Some day, someone should have a look at that nasty tty encoded. It's
 
81
 *  much simplier under ssh2. I just hope the defaults values are ok ...
 
82
 */
 
83
 
 
84
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
 
85
    int row) {
 
86
  ssh_session session = channel->session;
 
87
  ssh_string str = NULL;
 
88
  if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
 
89
    ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
 
90
    return SSH_ERROR;
 
91
  }
 
92
  str = ssh_string_from_char(terminal);
 
93
  if (str == NULL) {
 
94
    ssh_set_error_oom(session);
 
95
    return -1;
 
96
  }
 
97
 
 
98
  if (buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 ||
 
99
      buffer_add_ssh_string(session->out_buffer, str) < 0) {
 
100
    ssh_string_free(str);
 
101
    return -1;
 
102
  }
 
103
  ssh_string_free(str);
 
104
 
 
105
  if (buffer_add_u32(session->out_buffer, ntohl(row)) < 0 ||
 
106
      buffer_add_u32(session->out_buffer, ntohl(col)) < 0 ||
 
107
      buffer_add_u32(session->out_buffer, 0) < 0 || /* x */
 
108
      buffer_add_u32(session->out_buffer, 0) < 0 || /* y */
 
109
      buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */
 
110
    return -1;
 
111
  }
 
112
 
 
113
  ssh_log(session, SSH_LOG_FUNCTIONS, "Opening a ssh1 pty");
 
114
 
 
115
  if (packet_send(session) == SSH_ERROR) {
 
116
    return -1;
 
117
  }
 
118
  switch(channel->request_state){
 
119
    case SSH_CHANNEL_REQ_STATE_ERROR:
 
120
    case SSH_CHANNEL_REQ_STATE_PENDING:
 
121
    case SSH_CHANNEL_REQ_STATE_NONE:
 
122
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
123
      return SSH_ERROR;
 
124
    case SSH_CHANNEL_REQ_STATE_ACCEPTED:
 
125
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
126
      ssh_log(session, SSH_LOG_RARE, "PTY: Success");
 
127
      return SSH_OK;
 
128
    case SSH_CHANNEL_REQ_STATE_DENIED:
 
129
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
130
      ssh_set_error(session, SSH_REQUEST_DENIED,
 
131
          "Server denied PTY allocation");
 
132
      ssh_log(session, SSH_LOG_RARE, "PTY: denied\n");
 
133
      return SSH_ERROR;
 
134
  }
 
135
  // Not reached
 
136
  return SSH_ERROR;
 
137
}
 
138
 
 
139
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
 
140
  ssh_session session = channel->session;
 
141
  if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
 
142
    ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
 
143
    return SSH_ERROR;
 
144
  }
 
145
  if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
 
146
      buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
 
147
      buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
 
148
      buffer_add_u32(session->out_buffer, 0) < 0 ||
 
149
      buffer_add_u32(session->out_buffer, 0) < 0) {
 
150
    return SSH_ERROR;
 
151
  }
 
152
  channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
 
153
  if (packet_send(session) == SSH_ERROR) {
 
154
    return SSH_ERROR;
 
155
  }
 
156
 
 
157
  ssh_log(session, SSH_LOG_PROTOCOL, "Change pty size send");
 
158
  while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
 
159
    ssh_handle_packets(session,-1);
 
160
  }
 
161
  switch(channel->request_state){
 
162
    case SSH_CHANNEL_REQ_STATE_ERROR:
 
163
    case SSH_CHANNEL_REQ_STATE_PENDING:
 
164
    case SSH_CHANNEL_REQ_STATE_NONE:
 
165
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
166
      return SSH_ERROR;
 
167
    case SSH_CHANNEL_REQ_STATE_ACCEPTED:
 
168
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
169
      ssh_log(session, SSH_LOG_PROTOCOL, "pty size changed");
 
170
      return SSH_OK;
 
171
    case SSH_CHANNEL_REQ_STATE_DENIED:
 
172
      channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
 
173
      ssh_log(session, SSH_LOG_RARE, "pty size change denied");
 
174
      ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
 
175
      return SSH_ERROR;
 
176
  }
 
177
  // Not reached
 
178
  return SSH_ERROR;
 
179
 
 
180
}
 
181
 
 
182
int channel_request_shell1(ssh_channel channel) {
 
183
  ssh_session session = channel->session;
 
184
 
 
185
  if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
 
186
    return -1;
 
187
  }
 
188
 
 
189
  if (packet_send(session) == SSH_ERROR) {
 
190
    return -1;
 
191
  }
 
192
 
 
193
  ssh_log(session, SSH_LOG_RARE, "Launched a shell");
 
194
 
 
195
  return 0;
 
196
}
 
197
 
 
198
int channel_request_exec1(ssh_channel channel, const char *cmd) {
 
199
  ssh_session session = channel->session;
 
200
  ssh_string command = NULL;
 
201
 
 
202
  command = ssh_string_from_char(cmd);
 
203
  if (command == NULL) {
 
204
    return -1;
 
205
  }
 
206
 
 
207
  if (buffer_add_u8(session->out_buffer, SSH_CMSG_EXEC_CMD) < 0 ||
 
208
      buffer_add_ssh_string(session->out_buffer, command) < 0) {
 
209
    ssh_string_free(command);
 
210
    return -1;
 
211
  }
 
212
  ssh_string_free(command);
 
213
 
 
214
  if(packet_send(session) == SSH_ERROR) {
 
215
    return -1;
 
216
  }
 
217
 
 
218
  ssh_log(session, SSH_LOG_RARE, "Executing %s ...", cmd);
 
219
 
 
220
  return 0;
 
221
}
 
222
 
 
223
SSH_PACKET_CALLBACK(ssh_packet_data1){
 
224
    ssh_channel channel = session->channels;
 
225
    ssh_string str = NULL;
 
226
    int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
 
227
    (void)user;
 
228
    str = buffer_get_ssh_string(packet);
 
229
    if (str == NULL) {
 
230
      ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
 
231
      return SSH_PACKET_USED;
 
232
    }
 
233
 
 
234
    ssh_log(session, SSH_LOG_PROTOCOL,
 
235
        "Adding %" PRIdS " bytes data in %d",
 
236
        ssh_string_len(str), is_stderr);
 
237
 
 
238
    if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),
 
239
          is_stderr) < 0) {
 
240
      ssh_string_free(str);
 
241
      return SSH_PACKET_USED;
 
242
    }
 
243
    ssh_string_free(str);
 
244
 
 
245
    return SSH_PACKET_USED;
 
246
}
 
247
 
 
248
SSH_PACKET_CALLBACK(ssh_packet_close1){
 
249
  ssh_channel channel = session->channels;
 
250
  uint32_t status;
 
251
  (void)type;
 
252
  (void)user;
 
253
  buffer_get_u32(packet, &status);
 
254
  /*
 
255
   * It's much more than a channel closing. spec says it's the last
 
256
   * message sent by server (strange)
 
257
   */
 
258
 
 
259
  /* actually status is lost somewhere */
 
260
  channel->state = SSH_CHANNEL_STATE_CLOSED;
 
261
  channel->remote_eof = 1;
 
262
 
 
263
  buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
 
264
  packet_send(session);
 
265
 
 
266
  return SSH_PACKET_USED;
 
267
}
 
268
 
 
269
 
 
270
int channel_write1(ssh_channel channel, const void *data, int len) {
 
271
  ssh_session session = channel->session;
 
272
  int origlen = len;
 
273
  int effectivelen;
 
274
  const unsigned char *ptr=data;
 
275
  while (len > 0) {
 
276
    if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
 
277
      return -1;
 
278
    }
 
279
 
 
280
    effectivelen = len > 32000 ? 32000 : len;
 
281
 
 
282
    if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
 
283
        buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
 
284
      return -1;
 
285
    }
 
286
 
 
287
    ptr += effectivelen;
 
288
    len -= effectivelen;
 
289
 
 
290
    if (packet_send(session) == SSH_ERROR) {
 
291
      return -1;
 
292
    }
 
293
  }
 
294
 
 
295
  return origlen;
 
296
}
 
297
 
 
298
#endif /* WITH_SSH1 */
 
299
/* vim: set ts=2 sw=2 et cindent: */