예제 #1
0
파일: v6.c 프로젝트: pyokagan/sftpserver
uint32_t sftp_v6_link(struct sftpjob *job) {
  char *oldpath, *newlinkpath;
  uint8_t symbolic;
  struct stat sb;

  /* See also comment in v3.c for SSH_FXP_SYMLINK */
  if(readonly)
    return SSH_FX_PERMISSION_DENIED;
  pcheck(sftp_parse_path(job, &newlinkpath));
  pcheck(sftp_parse_path(job, &oldpath));    /* aka existing-path/target-paths */
  pcheck(sftp_parse_uint8(job, &symbolic));
  D(("sftp_link %s %s [%s]", oldpath, newlinkpath,
     symbolic ? "symbolic" : "hard"));
  if((symbolic ? symlink : link)(oldpath, newlinkpath) < 0) {
    switch(errno) {
    case EPERM:
      if(!symbolic && stat(oldpath, &sb) >= 0 && S_ISDIR(sb.st_mode))
        /* Can't hard-link directories */
        return SSH_FX_FILE_IS_A_DIRECTORY;
      else
        /* e.g. Linux returns EPERM for symlink or link on a FAT32 fs */
        return SSH_FX_OP_UNSUPPORTED;
      break;
    default:
      return HANDLER_ERRNO;
    }
  } else
    return SSH_FX_OK;
}
예제 #2
0
파일: v4.c 프로젝트: ewxrjk/sftpserver
uint32_t sftp_v456_stat(struct sftpjob *job) {
  char *path;
  struct stat sb;

  pcheck(sftp_parse_path(job, &path));
  D(("sftp_stat %s", path));
  return sftp_v456_stat_core(job, stat(path, &sb), &sb, path);
}
예제 #3
0
파일: v6.c 프로젝트: pyokagan/sftpserver
uint32_t sftp_v6_version_select(struct sftpjob *job) {
  char *newversion;

  /* If we've already created the work queue then this can't be the first
   * message. */
  if(!workqueue) {
    pcheck(sftp_parse_path(job, &newversion));
    /* Handle known versions */
    if(!strcmp(newversion, "3")) { protocol = &sftp_v3; return SSH_FX_OK; }
    if(!strcmp(newversion, "4")) { protocol = &sftp_v4; return SSH_FX_OK; }
    if(!strcmp(newversion, "5")) { protocol = &sftp_v5; return SSH_FX_OK; }
    if(!strcmp(newversion, "6")) { protocol = &sftp_v6; return SSH_FX_OK; }
    sftp_send_status(job, SSH_FX_INVALID_PARAMETER, "unknown version");
  } else
    sftp_send_status(job, SSH_FX_INVALID_PARAMETER, "badly timed version-select");
  /* We MUST close the channel.  (-13, s5.5). */
  exit(-1);
}
예제 #4
0
파일: v4.c 프로젝트: ewxrjk/sftpserver
uint32_t sftp_v456_parseattrs(struct sftpjob *job, struct sftpattr *attrs) {
  uint32_t n, rc;

  memset(attrs, 0, sizeof *attrs);
  if((rc = sftp_parse_uint32(job, &attrs->valid)) != SSH_FX_OK)
    return rc;
  if((attrs->valid & protocol->attrmask) != attrs->valid) {
    D(("received attrs %#x but protocol %d only supports %#x", attrs->valid,
       protocol->version, protocol->attrmask));
    attrs->valid = 0;
    return SSH_FX_BAD_MESSAGE;
  }
  if((rc = sftp_parse_uint8(job, &attrs->type)) != SSH_FX_OK)
    return rc;
  if(attrs->valid & SSH_FILEXFER_ATTR_SIZE)
    if((rc = sftp_parse_uint64(job, &attrs->size)) != SSH_FX_OK)
      return rc;
  if(attrs->valid & SSH_FILEXFER_ATTR_OWNERGROUP) {
    if((rc = sftp_parse_path(job, &attrs->owner)) != SSH_FX_OK)
      return rc;
    if((rc = sftp_parse_path(job, &attrs->group)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_PERMISSIONS) {
    if((rc = sftp_parse_uint32(job, &attrs->permissions)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_ACCESSTIME) {
    if((rc = sftp_parse_uint64(job, (uint64_t *)&attrs->atime.seconds)) !=
       SSH_FX_OK)
      return rc;
    if(attrs->valid & SSH_FILEXFER_ATTR_SUBSECOND_TIMES)
      if((rc = sftp_parse_uint32(job, &attrs->atime.nanoseconds)) != SSH_FX_OK)
        return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_CREATETIME) {
    if((rc = sftp_parse_uint64(job, (uint64_t *)&attrs->createtime.seconds)) !=
       SSH_FX_OK)
      return rc;
    if(attrs->valid & SSH_FILEXFER_ATTR_SUBSECOND_TIMES)
      if((rc = sftp_parse_uint32(job, &attrs->createtime.nanoseconds)) !=
         SSH_FX_OK)
        return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_MODIFYTIME) {
    if((rc = sftp_parse_uint64(job, (uint64_t *)&attrs->mtime.seconds)) !=
       SSH_FX_OK)
      return rc;
    if(attrs->valid & SSH_FILEXFER_ATTR_SUBSECOND_TIMES)
      if((rc = sftp_parse_uint32(job, &attrs->mtime.nanoseconds)) != SSH_FX_OK)
        return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_CTIME) {
    if((rc = sftp_parse_uint64(job, (uint64_t *)&attrs->ctime.seconds)) !=
       SSH_FX_OK)
      return rc;
    if(attrs->valid & SSH_FILEXFER_ATTR_SUBSECOND_TIMES)
      if((rc = sftp_parse_uint32(job, &attrs->ctime.nanoseconds)) != SSH_FX_OK)
        return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_ACL) {
    if((rc = sftp_parse_string(job, &attrs->acl, 0)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_BITS) {
    if((rc = sftp_parse_uint32(job, &attrs->attrib_bits)) != SSH_FX_OK)
      return rc;
    if(protocol->version >= 6) {
      if((rc = sftp_parse_uint32(job, &attrs->attrib_bits_valid)) != SSH_FX_OK)
        return rc;
    } else
      attrs->attrib_bits_valid = 0x7ff; /* -05 s5.8 */
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_TEXT_HINT) {
    if((rc = sftp_parse_uint8(job, &attrs->text_hint)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_MIME_TYPE) {
    if((rc = sftp_parse_string(job, &attrs->mime_type, 0)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_LINK_COUNT) {
    if((rc = sftp_parse_uint32(job, &attrs->link_count)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_UNTRANSLATED_NAME) {
    if((rc = sftp_parse_string(job, &attrs->mime_type, 0)) != SSH_FX_OK)
      return rc;
  }
  if(attrs->valid & SSH_FILEXFER_ATTR_EXTENDED) {
    if((rc = sftp_parse_uint32(job, &n)) != SSH_FX_OK)
      return rc;
    while(n-- > 0) {
      if((rc = sftp_parse_string(job, 0, 0)) != SSH_FX_OK)
        return rc;
      if((rc = sftp_parse_string(job, 0, 0)) != SSH_FX_OK)
        return rc;
    }
  }
  return SSH_FX_OK;
}
예제 #5
0
파일: v6.c 프로젝트: pyokagan/sftpserver
uint32_t sftp_v6_realpath(struct sftpjob *job) {
  char *path, *compose, *resolvedpath;
  uint8_t control_byte = SSH_FXP_REALPATH_NO_CHECK;
  unsigned rpflags = 0;
  struct stat sb;
  struct sftpattr attrs;

  pcheck(sftp_parse_path(job, &path));
  if(job->left) {
    pcheck(sftp_parse_uint8(job, &control_byte));
    while(job->left) {
      pcheck(sftp_parse_path(job, &compose));
      if(compose[0] == '/')
        path = compose;
      else {
        char *newpath = sftp_alloc(job->a, strlen(path) + strlen(compose) + 2);

        strcpy(newpath, path);
        strcat(newpath, "/");
        strcat(newpath, compose);
        path = newpath;
      }
    }
  }
  D(("sftp_v6_realpath %s %#x", path, control_byte));
  switch(control_byte) {
  case SSH_FXP_REALPATH_NO_CHECK:
    /* Don't follow links and don't fail if the path doesn't exist */
    rpflags = 0;
    break;
  case SSH_FXP_REALPATH_STAT_IF:
    /* Follow links but don't fail if the path doesn't exist */
    rpflags = RP_READLINK;
    break;
  case SSH_FXP_REALPATH_STAT_ALWAYS:
    /* Follow links and fail if the path doesn't exist */
    rpflags = RP_READLINK|RP_MUST_EXIST;
    break;
  default:
    return SSH_FX_BAD_MESSAGE;
  }
  if(!(resolvedpath = sftp_find_realpath(job->a, path, rpflags)))
    return HANDLER_ERRNO;
  D(("...real path is %s", resolvedpath));
  switch(control_byte) {
  case SSH_FXP_REALPATH_NO_CHECK:
    /* Don't stat, send dummy attributes */
    memset(&attrs, 0, sizeof attrs);
    attrs.name = resolvedpath;
    break;
  case SSH_FXP_REALPATH_STAT_IF:
    /* stat as hard as we can but accept failure if it's just not there */
    if(stat(resolvedpath, &sb) >= 0 || lstat(resolvedpath, &sb) >= 0)
      sftp_stat_to_attrs(job->a, &sb, &attrs, 0xFFFFFFFF, resolvedpath);
    else {
      memset(&attrs, 0, sizeof attrs);
      attrs.name = resolvedpath;
    }
    break;
  case SSH_FXP_REALPATH_STAT_ALWAYS:
    /* stat and error on failure */
    if(stat(resolvedpath, &sb) >= 0 || lstat(resolvedpath, &sb) >= 0)
      sftp_stat_to_attrs(job->a, &sb, &attrs, 0xFFFFFFFF, resolvedpath);
    else
      /* Can only happen if path is deleted between realpath call and stat */
      return HANDLER_ERRNO;
    break;
  }
  sftp_send_begin(job->worker);
  sftp_send_uint8(job->worker, SSH_FXP_NAME);
  sftp_send_uint32(job->worker, job->id);
  protocol->sendnames(job, 1, &attrs);
  sftp_send_end(job->worker);
  return HANDLER_RESPONDED;
}