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