1 /* scp.c contains the needed function to work with file transfer protocol over ssh*/ 2 /* don't look further if you believe this is just FTP over some tunnel. It IS different */ 3 /* This file contains code written by Nick Zitzmann */ 4 /* 5 Copyright 2003 Aris Adamantiadis 6 7 This file is part of the SSH Library 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 <fcntl.h> 27 #include <netdb.h> 28 #include "libssh/priv.h" 29 #include "libssh/ssh2.h" 30 #include "libssh/sftp.h" 31 #ifndef NO_SFTP 32 /* here how it works : sftp commands are channeled by the ssh sftp subsystem. */ 33 /* every packet are sent/read using a SFTP_PACKET type structure. */ 34 /* into these packets, most of the server answers are messages having an ID and */ 35 /* having a message specific part. it is described by SFTP_MESSAGE */ 36 /* when reading a message, the sftp system puts it into the queue, so the process having asked for it */ 37 /* can fetch it, while continuing to read for other messages (it is inspecified in which order messages may */ 38 /* be sent back to the client */ 39 40 41 /* functions */ 42 static void sftp_packet_free(SFTP_PACKET *packet); 43 void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg); 44 static void sftp_message_free(SFTP_MESSAGE *msg); 45 46 SFTP_SESSION *sftp_new(SSH_SESSION *session){ 47 SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION)); 48 memset(sftp,0,sizeof(SFTP_SESSION)); 49 sftp->session=session; 50 sftp->channel=open_session_channel(session,131000,32000); 51 if(!sftp->channel){ 52 free(sftp); 53 return NULL; 54 } 55 if(channel_request_sftp(sftp->channel)){ 56 sftp_free(sftp); 57 return NULL; 58 } 59 return sftp; 60 } 61 62 void sftp_free(SFTP_SESSION *sftp){ 63 struct request_queue *ptr; 64 channel_send_eof(sftp->channel); 65 /* let libssh handle the channel closing from the server reply */ 66 ptr=sftp->queue; 67 while(ptr){ 68 struct request_queue *old; 69 sftp_message_free(ptr->message); 70 old=ptr->next; 71 free(ptr); 72 ptr=old; 73 } 74 memset(sftp,0,sizeof(*sftp)); 75 free(sftp); 76 } 77 78 int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){ 79 u32 size; 80 buffer_add_data_begin(payload,&type,sizeof(u8)); 81 size=htonl(buffer_get_len(payload)); 82 buffer_add_data_begin(payload,&size,sizeof(u32)); 83 size=channel_write(sftp->channel,buffer_get(payload),buffer_get_len(payload)); 84 if(size != buffer_get_len(payload)){ 85 ssh_say(1,"had to write %d bytes, wrote only %d\n",buffer_get_len(payload),size); 86 } 87 return size; 88 } 89 90 SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){ 91 SFTP_PACKET *packet=malloc(sizeof(SFTP_PACKET)); 92 u32 size; 93 packet->sftp=sftp; 94 packet->payload=buffer_new(); 95 if(channel_read(sftp->channel,packet->payload,4,0)<=0){ 96 buffer_free(packet->payload); 97 free(packet); 98 return NULL; 99 } 100 buffer_get_u32(packet->payload,&size); 101 size=ntohl(size); 102 if(channel_read(sftp->channel,packet->payload,1,0)<=0){ 103 buffer_free(packet->payload); 104 free(packet); 105 return NULL; 106 } 107 buffer_get_u8(packet->payload,&packet->type); 108 if(size>1) 109 if(channel_read(sftp->channel,packet->payload,size-1,0)<=0){ 110 buffer_free(packet->payload); 111 free(packet); 112 return NULL; 113 } 114 return packet; 115 } 116 117 static SFTP_MESSAGE *sftp_message_new(){ 118 SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE)); 119 memset(msg,0,sizeof(*msg)); 120 msg->payload=buffer_new(); 121 return msg; 122 } 123 124 static void sftp_message_free(SFTP_MESSAGE *msg){ 125 if(msg->payload) 126 buffer_free(msg->payload); 127 free(msg); 128 } 129 130 SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet){ 131 SFTP_MESSAGE *msg=sftp_message_new(); 132 msg->sftp=packet->sftp; 133 msg->packet_type=packet->type; 134 if((packet->type!=SSH_FXP_STATUS)&&(packet->type!=SSH_FXP_HANDLE) && 135 (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS) 136 && (packet->type != SSH_FXP_NAME)){ 137 ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"get_message : unknown packet type %d\n",packet->type); 138 sftp_message_free(msg); 139 return NULL; 140 } 141 if(buffer_get_u32(packet->payload,&msg->id)!=sizeof(u32)){ 142 ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"invalid packet %d : no ID",packet->type); 143 sftp_message_free(msg); 144 return NULL; 145 } 146 ssh_say(2,"packet with id %d type %d\n",msg->id,msg->packet_type); 147 buffer_add_data(msg->payload,buffer_get_rest(packet->payload),buffer_get_rest_len(packet->payload)); 148 return msg; 149 } 150 151 int sftp_read_and_dispatch(SFTP_SESSION *session){ 152 SFTP_PACKET *packet; 153 SFTP_MESSAGE *message=NULL; 154 packet=sftp_packet_read(session); 155 if(!packet) 156 return -1; /* something nasty happened reading the packet */ 157 message=sftp_get_message(packet); 158 sftp_packet_free(packet); 159 if(!message) 160 return -1; 161 sftp_enqueue(session,message); 162 return 0; 163 } 164 165 static void sftp_packet_free(SFTP_PACKET *packet){ 166 if(packet->payload) 167 buffer_free(packet->payload); 168 free(packet); 169 } 170 171 int sftp_init(SFTP_SESSION *sftp){ 172 SFTP_PACKET *packet; 173 BUFFER *buffer=buffer_new(); 174 STRING *ext_name_s=NULL, *ext_data_s=NULL; 175 char *ext_name,*ext_data; 176 u32 version=htonl(LIBSFTP_VERSION); 177 buffer_add_u32(buffer,version); 178 sftp_packet_write(sftp,SSH_FXP_INIT,buffer); 179 buffer_free(buffer); 180 packet=sftp_packet_read(sftp); 181 if(!packet) 182 return -1; 183 if(packet->type != SSH_FXP_VERSION){ 184 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a %d messages instead of SSH_FXP_VERSION",packet->type); 185 sftp_packet_free(packet); 186 return -1; 187 } 188 buffer_get_u32(packet->payload,&version); 189 version=ntohl(version); 190 if(!(ext_name_s=buffer_get_ssh_string(packet->payload))||!(ext_data_s=buffer_get_ssh_string(packet->payload))) 191 ssh_say(2,"sftp server version %d\n",version); 192 else{ 193 ext_name=string_to_char(ext_name_s); 194 ext_data=string_to_char(ext_data_s); 195 ssh_say(2,"sftp server version %d (%s,%s)\n",version,ext_name,ext_data); 196 free(ext_name); 197 free(ext_data); 198 } 199 if(ext_name_s) 200 free(ext_name_s); 201 if(ext_data_s) 202 free(ext_data_s); 203 sftp_packet_free(packet); 204 sftp->server_version=version; 205 return 0; 206 } 207 208 REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg){ 209 REQUEST_QUEUE *queue=malloc(sizeof(REQUEST_QUEUE)); 210 memset(queue,0,sizeof(REQUEST_QUEUE)); 211 queue->message=msg; 212 return queue; 213 } 214 215 void request_queue_free(REQUEST_QUEUE *queue){ 216 memset(queue,0,sizeof(*queue)); 217 free(queue); 218 } 219 220 void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg){ 221 REQUEST_QUEUE *queue=request_queue_new(msg); 222 REQUEST_QUEUE *ptr; 223 ssh_say(2,"queued msg type %d id %d\n",msg->id,msg->packet_type); 224 if(!session->queue) 225 session->queue=queue; 226 else { 227 ptr=session->queue; 228 while(ptr->next){ 229 ptr=ptr->next; /* find end of linked list */ 230 } 231 ptr->next=queue; /* add it on bottom */ 232 } 233 } 234 235 /* pulls of a message from the queue based on the ID. returns null if no message has been found */ 236 SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *session, u32 id){ 237 REQUEST_QUEUE *queue,*prev=NULL; 238 SFTP_MESSAGE *msg; 239 if(session->queue==NULL){ 240 return NULL; 241 } 242 queue=session->queue; 243 while(queue){ 244 if(queue->message->id==id){ 245 /* remove from queue */ 246 if(prev==NULL){ 247 session->queue=queue->next; 248 } else { 249 prev->next=queue->next; 250 } 251 msg=queue->message; 252 request_queue_free(queue); 253 ssh_say(2,"dequeued msg id %d type %d\n",msg->id,msg->packet_type); 254 return msg; 255 } 256 prev=queue; 257 queue=queue->next; 258 } 259 return NULL; 260 } 261 262 /* assigns a new sftp ID for new requests and assures there is no collision between them. */ 263 u32 sftp_get_new_id(SFTP_SESSION *session){ 264 return ++session->id_counter; 265 } 266 267 STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){ 268 STATUS_MESSAGE *status; 269 if(msg->packet_type != SSH_FXP_STATUS){ 270 ssh_set_error(msg->sftp->session, SSH_INVALID_DATA,"Not a ssh_fxp_status message passed in !"); 271 return NULL; 272 } 273 status=malloc(sizeof(STATUS_MESSAGE)); 274 memset(status,0,sizeof(*status)); 275 status->id=msg->id; 276 if( (buffer_get_u32(msg->payload,&status->status)!= 4) 277 || !(status->error=buffer_get_ssh_string(msg->payload)) || 278 !(status->lang=buffer_get_ssh_string(msg->payload))){ 279 if(status->error) 280 free(status->error); 281 /* status->lang never get allocated if something failed */ 282 free(status); 283 ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"invalid SSH_FXP_STATUS message"); 284 return NULL; 285 } 286 status->status=ntohl(status->status); 287 status->errormsg=string_to_char(status->error); 288 status->langmsg=string_to_char(status->lang); 289 return status; 290 } 291 292 void status_msg_free(STATUS_MESSAGE *status){ 293 if(status->errormsg) 294 free(status->errormsg); 295 if(status->error) 296 free(status->error); 297 if(status->langmsg) 298 free(status->langmsg); 299 if(status->lang) 300 free(status->lang); 301 free(status); 302 } 303 304 SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){ 305 SFTP_FILE *file; 306 if(msg->packet_type != SSH_FXP_HANDLE){ 307 ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Not a ssh_fxp_handle message passed in !"); 308 return NULL; 309 } 310 file=malloc(sizeof(SFTP_FILE)); 311 memset(file,0,sizeof(*file)); 312 file->sftp=msg->sftp; 313 file->handle=buffer_get_ssh_string(msg->payload); 314 file->offset=0; 315 file->eof=0; 316 if(!file->handle){ 317 ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Invalid SSH_FXP_HANDLE message"); 318 free(file); 319 return NULL; 320 } 321 return file; 322 } 323 324 SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){ 325 SFTP_DIR *dir=NULL; 326 SFTP_FILE *file; 327 STATUS_MESSAGE *status; 328 SFTP_MESSAGE *msg=NULL; 329 STRING *path_s; 330 BUFFER *payload=buffer_new(); 331 u32 id=sftp_get_new_id(sftp); 332 buffer_add_u32(payload,id); 333 path_s=string_from_char(path); 334 buffer_add_ssh_string(payload,path_s); 335 free(path_s); 336 sftp_packet_write(sftp,SSH_FXP_OPENDIR,payload); 337 buffer_free(payload); 338 while(!msg){ 339 if(sftp_read_and_dispatch(sftp)) 340 /* something nasty has happened */ 341 return NULL; 342 msg=sftp_dequeue(sftp,id); 343 } 344 switch (msg->packet_type){ 345 case SSH_FXP_STATUS: 346 status=parse_status_msg(msg); 347 sftp_message_free(msg); 348 if(!status) 349 return NULL; 350 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); 351 status_msg_free(status); 352 return NULL; 353 case SSH_FXP_HANDLE: 354 file=parse_handle_msg(msg); 355 sftp_message_free(msg); 356 if(file){ 357 dir=malloc(sizeof(SFTP_DIR)); 358 memset(dir,0,sizeof(*dir)); 359 dir->sftp=sftp; 360 dir->name=strdup(path); 361 dir->handle=file->handle; 362 free(file); 363 } 364 return dir; 365 default: 366 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during opendir!",msg->packet_type); 367 sftp_message_free(msg); 368 } 369 return NULL; 370 } 371 372 /* parse the attributes from a payload from some messages */ 373 /* i coded it on baselines from the protocol version 4. */ 374 /* please excuse me for the inaccuracy of the code. it isn't my fault, it's sftp draft's one */ 375 /* this code is dead anyway ... */ 376 /* version 4 specific code */ 377 SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp,BUFFER *buf,int expectnames){ 378 u32 flags=0; 379 SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES)); 380 STRING *owner=NULL; 381 STRING *group=NULL; 382 int ok=0; 383 memset(attr,0,sizeof(*attr)); 384 /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */ 385 do { 386 if(buffer_get_u32(buf,&flags)!=4) 387 break; 388 flags=ntohl(flags); 389 attr->flags=flags; 390 if(flags & SSH_FILEXFER_ATTR_SIZE){ 391 if(buffer_get_u64(buf,&attr->size)!=8) 392 break; 393 attr->size=ntohll(attr->size); 394 } 395 if(flags & SSH_FILEXFER_ATTR_OWNERGROUP){ 396 if(!(owner=buffer_get_ssh_string(buf))) 397 break; 398 if(!(group=buffer_get_ssh_string(buf))) 399 break; 400 } 401 if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ 402 if(buffer_get_u32(buf,&attr->permissions)!=4) 403 break; 404 attr->permissions=ntohl(attr->permissions); 405 } 406 if(flags & SSH_FILEXFER_ATTR_ACCESSTIME){ 407 if(buffer_get_u64(buf,&attr->atime64)!=8) 408 break; 409 attr->atime64=ntohll(attr->atime64); 410 } 411 if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ 412 if(buffer_get_u32(buf,&attr->atime_nseconds)!=4) 413 break; 414 attr->atime_nseconds=ntohl(attr->atime_nseconds); 415 } 416 if(flags & SSH_FILEXFER_ATTR_CREATETIME){ 417 if(buffer_get_u64(buf,&attr->createtime)!=8) 418 break; 419 attr->createtime=ntohll(attr->createtime); 420 } 421 if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ 422 if(buffer_get_u32(buf,&attr->createtime_nseconds)!=4) 423 break; 424 attr->createtime_nseconds=ntohl(attr->createtime_nseconds); 425 } 426 if(flags & SSH_FILEXFER_ATTR_MODIFYTIME){ 427 if(buffer_get_u64(buf,&attr->mtime64)!=8) 428 break; 429 attr->mtime64=ntohll(attr->mtime64); 430 } 431 if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ 432 if(buffer_get_u32(buf,&attr->mtime_nseconds)!=4) 433 break; 434 attr->mtime_nseconds=ntohl(attr->mtime_nseconds); 435 } 436 if(flags & SSH_FILEXFER_ATTR_ACL){ 437 if(!(attr->acl=buffer_get_ssh_string(buf))) 438 break; 439 } 440 if (flags & SSH_FILEXFER_ATTR_EXTENDED){ 441 if(buffer_get_u32(buf,&attr->extended_count)!=4) 442 break; 443 attr->extended_count=ntohl(attr->extended_count); 444 while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf)) 445 && (attr->extended_data=buffer_get_ssh_string(buf))){ 446 attr->extended_count--; 447 } 448 if(attr->extended_count) 449 break; 450 } 451 ok=1; 452 } while (0); 453 if(!ok){ 454 /* break issued somewhere */ 455 if(owner) 456 free(owner); 457 if(group) 458 free(group); 459 if(attr->acl) 460 free(attr->acl); 461 if(attr->extended_type) 462 free(attr->extended_type); 463 if(attr->extended_data) 464 free(attr->extended_data); 465 free(attr); 466 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure"); 467 return NULL; 468 } 469 /* everything went smoothly */ 470 if(owner){ 471 attr->owner=string_to_char(owner); 472 free(owner); 473 } 474 if(group){ 475 attr->group=string_to_char(group); 476 free(group); 477 } 478 return attr; 479 } 480 481 /* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */ 482 /* maybe a paste of the draft is better than the code */ 483 /* 484 uint32 flags 485 uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE 486 uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID 487 uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID 488 uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS 489 uint32 atime present only if flag SSH_FILEXFER_ACMODTIME 490 uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME 491 uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED 492 string extended_type 493 string extended_data 494 ... more extended data (extended_type - extended_data pairs), 495 so that number of pairs equals extended_count */ 496 SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp,BUFFER *buf,int expectname){ 497 u32 flags=0; 498 STRING *name; 499 STRING *longname; 500 SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES)); 501 int ok=0; 502 memset(attr,0,sizeof(*attr)); 503 /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */ 504 do { 505 if(expectname){ 506 if(!(name=buffer_get_ssh_string(buf))) 507 break; 508 attr->name=string_to_char(name); 509 free(name); 510 ssh_say(2,"name : %s\n",attr->name); 511 if(!(longname=buffer_get_ssh_string(buf))) 512 break; 513 attr->longname=string_to_char(longname); 514 free(longname); 515 } 516 if(buffer_get_u32(buf,&flags)!=sizeof(u32)) 517 break; 518 flags=ntohl(flags); 519 attr->flags=flags; 520 ssh_say(2,"flags : %.8lx\n",flags); 521 if(flags & SSH_FILEXFER_ATTR_SIZE){ 522 if(buffer_get_u64(buf,&attr->size)!=sizeof(u64)) 523 break; 524 attr->size=ntohll(attr->size); 525 ssh_say(2,"size : %lld\n",attr->size); 526 } 527 if(flags & SSH_FILEXFER_ATTR_UIDGID){ 528 if(buffer_get_u32(buf,&attr->uid)!=sizeof(u32)) 529 break; 530 if(buffer_get_u32(buf,&attr->gid)!=sizeof(u32)) 531 break; 532 attr->uid=ntohl(attr->uid); 533 attr->gid=ntohl(attr->gid); 534 } 535 if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ 536 if(buffer_get_u32(buf,&attr->permissions)!=sizeof(u32)) 537 break; 538 attr->permissions=ntohl(attr->permissions); 539 } 540 if(flags & SSH_FILEXFER_ATTR_ACMODTIME){ 541 if(buffer_get_u32(buf,&attr->atime)!=sizeof(u32)) 542 break; 543 attr->atime=ntohl(attr->atime); 544 if(buffer_get_u32(buf,&attr->mtime)!=sizeof(u32)) 545 break; 546 attr->mtime=ntohl(attr->mtime); 547 } 548 if (flags & SSH_FILEXFER_ATTR_EXTENDED){ 549 if(buffer_get_u32(buf,&attr->extended_count)!=sizeof(u32)) 550 break; 551 attr->extended_count=ntohl(attr->extended_count); 552 while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf)) 553 && (attr->extended_data=buffer_get_ssh_string(buf))){ 554 attr->extended_count--; 555 } 556 if(attr->extended_count) 557 break; 558 } 559 ok=1; 560 } while (0); 561 if(!ok){ 562 /* break issued somewhere */ 563 if(attr->name) 564 free(attr->name); 565 if(attr->extended_type) 566 free(attr->extended_type); 567 if(attr->extended_data) 568 free(attr->extended_data); 569 free(attr); 570 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure"); 571 return NULL; 572 } 573 /* everything went smoothly */ 574 return attr; 575 } 576 577 void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){ 578 u32 flags=(attr?attr->flags:0); 579 flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME); 580 buffer_add_u32(buffer,htonl(flags)); 581 if(attr){ 582 if (flags & SSH_FILEXFER_ATTR_SIZE) 583 { 584 buffer_add_u64(buffer, htonll(attr->size)); 585 } 586 if(flags & SSH_FILEXFER_ATTR_UIDGID){ 587 buffer_add_u32(buffer,htonl(attr->uid)); 588 buffer_add_u32(buffer,htonl(attr->gid)); 589 } 590 if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ 591 buffer_add_u32(buffer,htonl(attr->permissions)); 592 } 593 if (flags & SSH_FILEXFER_ATTR_ACMODTIME) 594 { 595 buffer_add_u32(buffer, htonl(attr->atime)); 596 buffer_add_u32(buffer, htonl(attr->mtime)); 597 } 598 } 599 } 600 601 602 SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){ 603 switch(session->server_version){ 604 case 4: 605 return sftp_parse_attr_4(session,buf,expectname); 606 case 3: 607 return sftp_parse_attr_3(session,buf,expectname); 608 default: 609 ssh_set_error(session->session,SSH_INVALID_DATA,"Version %d unsupported by client",session->server_version); 610 return NULL; 611 } 612 return NULL; 613 } 614 615 int sftp_server_version(SFTP_SESSION *sftp){ 616 return sftp->server_version; 617 } 618 619 SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){ 620 BUFFER *payload; 621 u32 id; 622 SFTP_MESSAGE *msg=NULL; 623 STATUS_MESSAGE *status; 624 SFTP_ATTRIBUTES *attr; 625 if(!dir->buffer){ 626 payload=buffer_new(); 627 id=sftp_get_new_id(sftp); 628 buffer_add_u32(payload,id); 629 buffer_add_ssh_string(payload,dir->handle); 630 sftp_packet_write(sftp,SSH_FXP_READDIR,payload); 631 buffer_free(payload); 632 ssh_say(2,"sent a ssh_fxp_readdir with id %d\n",id); 633 while(!msg){ 634 if(sftp_read_and_dispatch(sftp)) 635 /* something nasty has happened */ 636 return NULL; 637 msg=sftp_dequeue(sftp,id); 638 } 639 switch (msg->packet_type){ 640 case SSH_FXP_STATUS: 641 status=parse_status_msg(msg); 642 sftp_message_free(msg); 643 if(!status) 644 return NULL; 645 if(status->status==SSH_FX_EOF){ 646 dir->eof=1; 647 status_msg_free(status); 648 return NULL; 649 } 650 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Unknown error status : %d",status->status); 651 status_msg_free(status); 652 return NULL; 653 case SSH_FXP_NAME: 654 buffer_get_u32(msg->payload,&dir->count); 655 dir->count=ntohl(dir->count); 656 dir->buffer=msg->payload; 657 msg->payload=NULL; 658 sftp_message_free(msg); 659 break; 660 default: 661 ssh_set_error(sftp->session,SSH_INVALID_DATA,"unsupported message back %d",msg->packet_type); 662 sftp_message_free(msg); 663 return NULL; 664 } 665 } 666 /* now dir->buffer contains a buffer and dir->count != 0 */ 667 if(dir->count==0){ 668 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Count of files sent by the server is zero, which is invalid, or libsftp bug"); 669 return NULL; 670 } 671 ssh_say(2,"Count is %d\n",dir->count); 672 attr=sftp_parse_attr(sftp,dir->buffer,1); 673 dir->count--; 674 if(dir->count==0){ 675 buffer_free(dir->buffer); 676 dir->buffer=NULL; 677 } 678 return attr; 679 } 680 681 int sftp_dir_eof(SFTP_DIR *dir){ 682 return (dir->eof); 683 } 684 685 void sftp_attributes_free(SFTP_ATTRIBUTES *file){ 686 if(file->name) 687 free(file->name); 688 if(file->longname) 689 free(file->longname); 690 if(file->acl) 691 free(file->acl); 692 if(file->extended_data) 693 free(file->extended_data); 694 if(file->extended_type) 695 free(file->extended_type); 696 if(file->group) 697 free(file->group); 698 if(file->owner) 699 free(file->owner); 700 free(file); 701 } 702 703 static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){ 704 SFTP_MESSAGE *msg=NULL; 705 STATUS_MESSAGE *status; 706 int id=sftp_get_new_id(sftp); 707 int err=0; 708 BUFFER *buffer=buffer_new(); 709 buffer_add_u32(buffer,id); 710 buffer_add_ssh_string(buffer,handle); 711 sftp_packet_write(sftp,SSH_FXP_CLOSE,buffer); 712 buffer_free(buffer); 713 while(!msg){ 714 if(sftp_read_and_dispatch(sftp)) 715 /* something nasty has happened */ 716 return -1; 717 msg=sftp_dequeue(sftp,id); 718 } 719 switch (msg->packet_type){ 720 case SSH_FXP_STATUS: 721 status=parse_status_msg(msg); 722 sftp_message_free(msg); 723 if(!status) 724 return -1; 725 if(status->status != SSH_FX_OK){ 726 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); 727 err=-1; 728 } 729 status_msg_free(status); 730 return err; 731 default: 732 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during sftp_handle_close!",msg->packet_type); 733 sftp_message_free(msg); 734 } 735 return -1; 736 } 737 738 int sftp_file_close(SFTP_FILE *file){ 739 int err=0; 740 if(file->name) 741 free(file->name); 742 if(file->handle){ 743 err=sftp_handle_close(file->sftp,file->handle); 744 free(file->handle); 745 } 746 free(file); 747 return err; 748 } 749 750 int sftp_dir_close(SFTP_DIR *dir){ 751 int err=0; 752 if(dir->name) 753 free(dir->name); 754 if(dir->handle){ 755 err=sftp_handle_close(dir->sftp,dir->handle); 756 free(dir->handle); 757 } 758 if(dir->buffer) 759 buffer_free(dir->buffer); 760 free(dir); 761 return err; 762 } 763 764 SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){ 765 SFTP_FILE *handle; 766 SFTP_MESSAGE *msg=NULL; 767 STATUS_MESSAGE *status; 768 u32 flags=0; 769 u32 id=sftp_get_new_id(sftp); 770 BUFFER *buffer=buffer_new(); 771 STRING *filename; 772 if(access & O_RDONLY) 773 flags|=SSH_FXF_READ; 774 if(access & O_WRONLY) 775 flags |= SSH_FXF_WRITE; 776 if(access & O_RDWR) 777 flags|=(SSH_FXF_WRITE | SSH_FXF_READ); 778 if(access & O_CREAT) 779 flags |=SSH_FXF_CREAT; 780 if(access & O_TRUNC) 781 flags |=SSH_FXF_TRUNC; 782 if(access & O_EXCL) 783 flags |= SSH_FXF_EXCL; 784 buffer_add_u32(buffer,id); 785 filename=string_from_char(file); 786 buffer_add_ssh_string(buffer,filename); 787 free(filename); 788 buffer_add_u32(buffer,htonl(flags)); 789 buffer_add_attributes(buffer,attr); 790 sftp_packet_write(sftp,SSH_FXP_OPEN,buffer); 791 buffer_free(buffer); 792 while(!msg){ 793 if(sftp_read_and_dispatch(sftp)) 794 /* something nasty has happened */ 795 return NULL; 796 msg=sftp_dequeue(sftp,id); 797 } 798 switch (msg->packet_type){ 799 case SSH_FXP_STATUS: 800 status=parse_status_msg(msg); 801 sftp_message_free(msg); 802 if(!status) 803 return NULL; 804 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); 805 status_msg_free(status); 806 return NULL; 807 case SSH_FXP_HANDLE: 808 handle=parse_handle_msg(msg); 809 sftp_message_free(msg); 810 return handle; 811 default: 812 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during open!",msg->packet_type); 813 sftp_message_free(msg); 814 } 815 return NULL; 816 } 817 818 void sftp_file_set_nonblocking(SFTP_FILE *handle){ 819 handle->nonblocking=1; 820 } 821 void sftp_file_set_blocking(SFTP_FILE *handle){ 822 handle->nonblocking=0; 823 } 824 825 int sftp_read(SFTP_FILE *handle, void *data, int len){ 826 SFTP_MESSAGE *msg=NULL; 827 STATUS_MESSAGE *status; 828 SFTP_SESSION *sftp=handle->sftp; 829 STRING *datastring; 830 int id; 831 int err=0; 832 BUFFER *buffer; 833 if(handle->eof) 834 return 0; 835 buffer=buffer_new(); 836 id=sftp_get_new_id(handle->sftp); 837 buffer_add_u32(buffer,id); 838 buffer_add_ssh_string(buffer,handle->handle); 839 buffer_add_u64(buffer,htonll(handle->offset)); 840 buffer_add_u32(buffer,htonl(len)); 841 sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer); 842 buffer_free(buffer); 843 while(!msg){ 844 if (handle->nonblocking){ 845 if(channel_poll(handle->sftp->channel,0)==0){ 846 /* we cannot block */ 847 return 0; 848 } 849 } 850 if(sftp_read_and_dispatch(handle->sftp)) 851 /* something nasty has happened */ 852 return -1; 853 msg=sftp_dequeue(handle->sftp,id); 854 } 855 switch (msg->packet_type){ 856 case SSH_FXP_STATUS: 857 status=parse_status_msg(msg); 858 sftp_message_free(msg); 859 if(!status) 860 return -1; 861 if(status->status != SSH_FX_EOF){ 862 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); 863 err=-1; 864 } 865 else 866 handle->eof=1; 867 status_msg_free(status); 868 return err?err:0; 869 case SSH_FXP_DATA: 870 datastring=buffer_get_ssh_string(msg->payload); 871 sftp_message_free(msg); 872 if(!datastring){ 873 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received invalid DATA packet from sftp server"); 874 return -1; 875 } 876 if(string_len(datastring)>len){ 877 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a too big DATA packet from sftp server : %d and asked for %d", 878 string_len(datastring),len); 879 free(datastring); 880 return -1; 881 } 882 len=string_len(datastring); 883 handle->offset+=len; 884 memcpy(data,datastring->string,len); 885 free(datastring); 886 return len; 887 default: 888 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during read!",msg->packet_type); 889 sftp_message_free(msg); 890 return -1; 891 } 892 return -1; /* not reached */ 893 } 894 895 int sftp_write(SFTP_FILE *file, void *data, int len){ 896 SFTP_MESSAGE *msg=NULL; 897 STATUS_MESSAGE *status; 898 STRING *datastring; 899 SFTP_SESSION *sftp=file->sftp; 900 int id; 901 int err=0; 902 BUFFER *buffer; 903 buffer=buffer_new(); 904 id=sftp_get_new_id(file->sftp); 905 buffer_add_u32(buffer,id); 906 buffer_add_ssh_string(buffer,file->handle); 907 buffer_add_u64(buffer,htonll(file->offset)); 908 datastring=string_new(len); 909 string_fill(datastring,data,len); 910 buffer_add_ssh_string(buffer,datastring); 911 free(datastring); 912 if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){ 913 ssh_say(1,"sftp_packet_write did not write as much data as expected\n"); 914 } 915 buffer_free(buffer); 916 while(!msg){ 917 if(sftp_read_and_dispatch(file->sftp)) 918 /* something nasty has happened */ 919 return -1; 920 msg=sftp_dequeue(file->sftp,id); 921 } 922 switch (msg->packet_type){ 923 case SSH_FXP_STATUS: 924 status=parse_status_msg(msg); 925 sftp_message_free(msg); 926 if(!status) 927 return -1; 928 if(status->status != SSH_FX_OK){ 929 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); 930 err=-1; 931 } 932 file->offset+=len; 933 status_msg_free(status); 934 return (err?err:len); 935 default: 936 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during write!",msg->packet_type); 937 sftp_message_free(msg); 938 return -1; 939 } 940 return -1; /* not reached */ 941 } 942 943 void sftp_seek(SFTP_FILE *file, int new_offset){ 944 file->offset=new_offset; 945 } 946 947 unsigned long sftp_tell(SFTP_FILE *file){ 948 return file->offset; 949 } 950 951 void sftp_rewind(SFTP_FILE *file){ 952 file->offset=0; 953 } 954 955 /* code written by Nick */ 956 int sftp_rm(SFTP_SESSION *sftp, char *file) { 957 u32 id = sftp_get_new_id(sftp); 958 BUFFER *buffer = buffer_new(); 959 STRING *filename = string_from_char(file); 960 SFTP_MESSAGE *msg = NULL; 961 STATUS_MESSAGE *status = NULL; 962 963 buffer_add_u32(buffer, id); 964 buffer_add_ssh_string(buffer, filename); 965 free(filename); 966 sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer); 967 buffer_free(buffer); 968 while (!msg) { 969 if (sftp_read_and_dispatch(sftp)) { 970 return -1; 971 } 972 msg = sftp_dequeue(sftp, id); 973 } 974 if (msg->packet_type == SSH_FXP_STATUS) { 975 /* by specification, this command's only supposed to return SSH_FXP_STATUS */ 976 status = parse_status_msg(msg); 977 sftp_message_free(msg); 978 if (!status) 979 return -1; 980 if (status->status != SSH_FX_OK) { 981 /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ 982 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 983 status_msg_free(status); 984 return -1; 985 } 986 status_msg_free(status); 987 return 0; /* at this point, everything turned out OK */ 988 } else { 989 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove file", msg->packet_type); 990 sftp_message_free(msg); 991 } 992 return -1; 993 } 994 995 /* code written by Nick */ 996 int sftp_rmdir(SFTP_SESSION *sftp, char *directory) { 997 u32 id = sftp_get_new_id(sftp); 998 BUFFER *buffer = buffer_new(); 999 STRING *filename = string_from_char(directory); 1000 SFTP_MESSAGE *msg = NULL; 1001 STATUS_MESSAGE *status = NULL; 1002 1003 buffer_add_u32(buffer, id); 1004 buffer_add_ssh_string(buffer, filename); 1005 free(filename); 1006 sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer); 1007 buffer_free(buffer); 1008 while (!msg) { 1009 if (sftp_read_and_dispatch(sftp)) 1010 { 1011 return -1; 1012 } 1013 msg = sftp_dequeue(sftp, id); 1014 } 1015 if (msg->packet_type == SSH_FXP_STATUS) /* by specification, this command's only supposed to return SSH_FXP_STATUS */ 1016 { 1017 status = parse_status_msg(msg); 1018 sftp_message_free(msg); 1019 if (!status) 1020 { 1021 return -1; 1022 } 1023 else if (status->status != SSH_FX_OK) /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ 1024 { 1025 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 1026 status_msg_free(status); 1027 return -1; 1028 } 1029 status_msg_free(status); 1030 return 0; /* at this point, everything turned out OK */ 1031 } 1032 else 1033 { 1034 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove directory", msg->packet_type); 1035 sftp_message_free(msg); 1036 } 1037 return -1; 1038 } 1039 1040 /* Code written by Nick */ 1041 int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) { 1042 u32 id = sftp_get_new_id(sftp); 1043 BUFFER *buffer = buffer_new(); 1044 STRING *path = string_from_char(directory); 1045 SFTP_MESSAGE *msg = NULL; 1046 STATUS_MESSAGE *status = NULL; 1047 1048 buffer_add_u32(buffer, id); 1049 buffer_add_ssh_string(buffer, path); 1050 free(path); 1051 buffer_add_attributes(buffer, attr); 1052 sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer); 1053 buffer_free(buffer); 1054 while (!msg) { 1055 if (sftp_read_and_dispatch(sftp)) 1056 return -1; 1057 msg = sftp_dequeue(sftp, id); 1058 } 1059 if (msg->packet_type == SSH_FXP_STATUS) { 1060 /* by specification, this command's only supposed to return SSH_FXP_STATUS */ 1061 status = parse_status_msg(msg); 1062 sftp_message_free(msg); 1063 if (!status) 1064 return -1; 1065 else 1066 if (status->status != SSH_FX_OK) { 1067 /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ 1068 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 1069 status_msg_free(status); 1070 return -1; 1071 } 1072 status_msg_free(status); 1073 return 0; /* at this point, everything turned out OK */ 1074 } else { 1075 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to make directory", msg->packet_type); 1076 sftp_message_free(msg); 1077 } 1078 return -1; 1079 } 1080 1081 /* code written by nick */ 1082 int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) { 1083 u32 id = sftp_get_new_id(sftp); 1084 BUFFER *buffer = buffer_new(); 1085 STRING *oldpath = string_from_char(original); 1086 STRING *newpath = string_from_char(newname); 1087 SFTP_MESSAGE *msg = NULL; 1088 STATUS_MESSAGE *status = NULL; 1089 1090 buffer_add_u32(buffer, id); 1091 buffer_add_ssh_string(buffer, oldpath); 1092 free(oldpath); 1093 buffer_add_ssh_string(buffer, newpath); 1094 free(newpath); 1095 sftp_packet_write(sftp, SSH_FXP_RENAME, buffer); 1096 buffer_free(buffer); 1097 while (!msg) { 1098 if (sftp_read_and_dispatch(sftp)) 1099 return -1; 1100 msg = sftp_dequeue(sftp, id); 1101 } 1102 if (msg->packet_type == SSH_FXP_STATUS) { 1103 /* by specification, this command's only supposed to return SSH_FXP_STATUS */ 1104 status = parse_status_msg(msg); 1105 sftp_message_free(msg); 1106 if (!status) 1107 return -1; 1108 else if (status->status != SSH_FX_OK) { 1109 /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ 1110 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 1111 status_msg_free(status); 1112 return -1; 1113 } 1114 status_msg_free(status); 1115 return 0; /* at this point, everything turned out OK */ 1116 } else { 1117 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to rename", msg->packet_type); 1118 sftp_message_free(msg); 1119 } 1120 return -1; 1121 } 1122 1123 /* Code written by Nick */ 1124 int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) { 1125 u32 id = sftp_get_new_id(sftp); 1126 BUFFER *buffer = buffer_new(); 1127 STRING *path = string_from_char(file); 1128 SFTP_MESSAGE *msg = NULL; 1129 STATUS_MESSAGE *status = NULL; 1130 1131 buffer_add_u32(buffer, id); 1132 buffer_add_ssh_string(buffer, path); 1133 free(path); 1134 buffer_add_attributes(buffer, attr); 1135 sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer); 1136 buffer_free(buffer); 1137 while (!msg) { 1138 if (sftp_read_and_dispatch(sftp)) 1139 return -1; 1140 msg = sftp_dequeue(sftp, id); 1141 } 1142 if (msg->packet_type == SSH_FXP_STATUS) { 1143 /* by specification, this command's only supposed to return SSH_FXP_STATUS */ 1144 status = parse_status_msg(msg); 1145 sftp_message_free(msg); 1146 if (!status) 1147 return -1; 1148 else if (status->status != SSH_FX_OK) { 1149 /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ 1150 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 1151 status_msg_free(status); 1152 return -1; 1153 } 1154 status_msg_free(status); 1155 return 0; /* at this point, everything turned out OK */ 1156 } else { 1157 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type); 1158 sftp_message_free(msg); 1159 } 1160 return -1; 1161 } 1162 1163 /* another code written by Nick */ 1164 char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path) 1165 { 1166 u32 id = sftp_get_new_id(sftp); 1167 BUFFER *buffer = buffer_new(); 1168 STRING *pathstr = string_from_char(path); 1169 STRING *name = NULL; 1170 SFTP_MESSAGE *msg = NULL; 1171 STATUS_MESSAGE *status = NULL; 1172 char *cname; 1173 u32 ignored; 1174 1175 buffer_add_u32(buffer, id); 1176 buffer_add_ssh_string(buffer, pathstr); 1177 free(pathstr); 1178 sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer); 1179 buffer_free(buffer); 1180 while (!msg) 1181 { 1182 if (sftp_read_and_dispatch(sftp)) 1183 return NULL; 1184 msg = sftp_dequeue(sftp, id); 1185 } 1186 if (msg->packet_type == SSH_FXP_NAME) /* good response */ 1187 { 1188 buffer_get_u32(msg->payload, &ignored); /* we don't care about "count" */ 1189 name = buffer_get_ssh_string(msg->payload); /* we only care about the file name string */ 1190 cname = string_to_char(name); 1191 free(name); 1192 return cname; 1193 } 1194 else if (msg->packet_type == SSH_FXP_STATUS) /* bad response (error) */ 1195 { 1196 status = parse_status_msg(msg); 1197 sftp_message_free(msg); 1198 if (!status) 1199 return NULL; 1200 ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); 1201 status_msg_free(status); 1202 } 1203 else /* this shouldn't happen */ 1204 { 1205 ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type); 1206 sftp_message_free(msg); 1207 } 1208 return NULL; 1209 } 1210 1211 SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){ 1212 u32 id=sftp_get_new_id(sftp); 1213 BUFFER *buffer=buffer_new(); 1214 STRING *pathstr= string_from_char(path); 1215 SFTP_MESSAGE *msg=NULL; 1216 STATUS_MESSAGE *status=NULL; 1217 SFTP_ATTRIBUTES *pattr=NULL; 1218 1219 buffer_add_u32(buffer,id); 1220 buffer_add_ssh_string(buffer,pathstr); 1221 free(pathstr); 1222 sftp_packet_write(sftp,param,buffer); 1223 buffer_free(buffer); 1224 while(!msg){ 1225 if(sftp_read_and_dispatch(sftp)) 1226 return NULL; 1227 msg=sftp_dequeue(sftp,id); 1228 } 1229 if(msg->packet_type==SSH_FXP_ATTRS){ 1230 pattr=sftp_parse_attr(sftp,msg->payload,0); 1231 return pattr; 1232 } 1233 if(msg->packet_type== SSH_FXP_STATUS){ 1234 status=parse_status_msg(msg); 1235 sftp_message_free(msg); 1236 if(!status) 1237 return NULL; 1238 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg); 1239 status_msg_free(status); 1240 return NULL; 1241 } 1242 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received mesg %d during stat(),mesg->packet_type"); 1243 sftp_message_free(msg); 1244 return NULL; 1245 } 1246 1247 SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){ 1248 return sftp_xstat(session,path,SSH_FXP_STAT); 1249 } 1250 SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){ 1251 return sftp_xstat(session,path,SSH_FXP_LSTAT); 1252 } 1253 1254 SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) { 1255 u32 id=sftp_get_new_id(file->sftp); 1256 BUFFER *buffer=buffer_new(); 1257 SFTP_MESSAGE *msg=NULL; 1258 STATUS_MESSAGE *status=NULL; 1259 SFTP_ATTRIBUTES *pattr=NULL; 1260 1261 buffer_add_u32(buffer,id); 1262 buffer_add_ssh_string(buffer,file->handle); 1263 sftp_packet_write(file->sftp,SSH_FXP_FSTAT,buffer); 1264 buffer_free(buffer); 1265 while(!msg){ 1266 if(sftp_read_and_dispatch(file->sftp)) 1267 return NULL; 1268 msg=sftp_dequeue(file->sftp,id); 1269 } 1270 if(msg->packet_type==SSH_FXP_ATTRS){ 1271 pattr=sftp_parse_attr(file->sftp,msg->payload,0); 1272 return pattr; 1273 } 1274 if(msg->packet_type== SSH_FXP_STATUS){ 1275 status=parse_status_msg(msg); 1276 sftp_message_free(msg); 1277 if(!status) 1278 return NULL; 1279 ssh_set_error(file->sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg); 1280 status_msg_free(status); 1281 return NULL; 1282 } 1283 ssh_set_error(file->sftp->session,SSH_INVALID_DATA,"Received mesg %d during fstat(),mesg->packet_type"); 1284 sftp_message_free(msg); 1285 return NULL; 1286 } 1287 1288 1289 #endif /* NO_SFTP */ |