Beispiel #1
0
smb_file  *smb_find(smb_session *s, smb_tid tid, const char *pattern)
{
  smb_message           *msg;
  smb_trans2_req        *tr2;
  smb_tr2_find2         *find;
  size_t                pattern_len, msg_len;
  int                   res;

  assert(s != NULL && pattern != NULL && tid);

  pattern_len = strlen(pattern) + 1;
  msg_len     = sizeof(smb_trans2_req) + sizeof(smb_tr2_find2);
  msg_len    += pattern_len * 2 + 3;

  msg = smb_message_new(SMB_CMD_TRANS2, msg_len);
  smb_message_set_default_flags(msg);
  msg->packet->header.tid = tid;

  tr2 = (smb_trans2_req *)msg->packet->payload;
  tr2->wct                = 15;
  tr2->total_param_count  = pattern_len * 2 + sizeof(smb_tr2_find2);
  tr2->max_param_count    = 10; // ?? Why not the same or 12 ?
  tr2->max_data_count     = 0xffff;
  tr2->param_count        = tr2->total_param_count;
  tr2->param_offset       = 68; // Offset of find_first_params in packet;
  tr2->data_count         = 0;
  tr2->data_offset        = 88; // Offset of pattern in packet
  tr2->setup_count        = 1;
  tr2->cmd                = SMB_TR2_FIND_FIRST;
  tr2->bct                = sizeof(smb_tr2_find2) + pattern_len * 2 + 3;

  find = (smb_tr2_find2 *) tr2->payload;
  find->attrs     = SMB_FIND2_ATTR_DEFAULT;
  find->count     = 1366;     // ??
  find->flags     = SMB_FIND2_FLAG_DEFAULT;
  find->interest  = 0x0104;   // 'Find file both directory info'

  smb_message_advance(msg, sizeof(smb_trans2_req));
  smb_message_advance(msg, sizeof(smb_tr2_find2));
  smb_message_put_utf16(msg, "", pattern, pattern_len);

  // Adds padding at the end if necessary.
  if (tr2->bct % 4)
    smb_message_advance(msg, 4 - tr2->bct % 4);

  res = smb_session_send_msg(s, msg);
  smb_message_destroy(msg);
  if (!res)
  {
    BDSM_dbg("Unable to query pattern: %s\n", pattern);
    return (NULL);
  }

  if ((msg = smb_tr2_recv(s)) == NULL)
    return (NULL);

  return (smb_find_parse(msg));
}
Beispiel #2
0
ssize_t   smb_fread(smb_session *s, smb_fd fd, void *buf, size_t buf_size)
{
    smb_file        *file;
    smb_message     *req_msg, resp_msg;
    smb_read_req    req;
    smb_read_resp   *resp;
    size_t          max_read;
    int             res;

    assert(s != NULL && buf != NULL);
    if (!fd)
      return (-1);
    if ((file = smb_session_file_get(s, fd)) == NULL)
        return (-1);

    req_msg = smb_message_new(SMB_CMD_READ);
    if (!req_msg)
        return (-1);
    req_msg->packet->header.tid = file->tid;

    max_read = 0xffff;
    max_read = max_read < buf_size ? max_read : buf_size;

    SMB_MSG_INIT_PKT_ANDX(req);
    req.wct              = 12;
    req.fid              = file->fid;
    req.offset           = file->readp;
    req.max_count        = max_read;
    req.min_count        = max_read;
    req.max_count_high   = 0;
    req.remaining        = 0;
    req.offset_high      = 0;
    req.bct              = 0;
    SMB_MSG_PUT_PKT(req_msg, req);

    res = smb_session_send_msg(s, req_msg);
    smb_message_destroy(req_msg);
    if (!res)
        return (-1);

    if (!smb_session_recv_msg(s, &resp_msg))
        return (-1);
    if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
        return (-1);

    resp = (smb_read_resp *)resp_msg.packet->payload;
    memcpy(buf, resp->file, resp->data_len);
    smb_fseek(s, fd, resp->data_len, SEEK_CUR);

    return (resp->data_len);
}
Beispiel #3
0
int           smb_tree_disconnect(smb_session *s, smb_tid tid)
{
    smb_tree_disconnect_req   req;
    smb_tree_disconnect_resp *resp;
    smb_message              *req_msg;
    smb_message               resp_msg;

    assert(s != NULL);

    if( s != NULL) {

        req_msg = smb_message_new(SMB_CMD_TREE_DISCONNECT);
        if (!req_msg)
            return DSM_ERROR_GENERIC;

        // Packet headers
        req_msg->packet->header.tid = (uint16_t)tid;

        // Packet payload
        req.wct = 0; // Must be 0
        req.bct = 0; // Must be 0
        SMB_MSG_PUT_PKT(req_msg, req);

        if (!smb_session_send_msg(s, req_msg))
        {
            smb_message_destroy(req_msg);
            return DSM_ERROR_NETWORK;
        }
        smb_message_destroy(req_msg);

        if (!smb_session_recv_msg(s, &resp_msg))
            return DSM_ERROR_NETWORK;
        if (!smb_session_check_nt_status(s, &resp_msg))
            return DSM_ERROR_NT;

        resp  = (smb_tree_disconnect_resp *)resp_msg.packet->payload;
        if ((resp->wct != 0) || (resp->bct != 0))
            return DSM_ERROR_NETWORK;

        return DSM_SUCCESS;
    }

    return DSM_ERROR_GENERIC;
}
Beispiel #4
0
void        smb_fclose(smb_session *s, smb_fd fd)
{
    smb_file        *file;
    smb_message     *msg;
    smb_close_req   req;

    assert(s != NULL);
    if (!fd)
      return;

    // XXX Memory leak, destroy the file after removing it
    if ((file = smb_session_file_remove(s, fd)) == NULL)
        return;

    msg = smb_message_new(SMB_CMD_CLOSE);
    if (!msg) {
        free(file->name);
        free(file);
        return;
    }

    msg->packet->header.tid = SMB_FD_TID(fd);

    SMB_MSG_INIT_PKT(req);
    req.wct        = 3;
    req.fid        = SMB_FD_FID(fd);
    req.last_write = ~0;
    req.bct        = 0;
    SMB_MSG_PUT_PKT(msg, req);

    // We don't check for succes or failure, since we actually don't really
    // care about creating a potentiel leak server side.
    smb_session_send_msg(s, msg);
    smb_session_recv_msg(s, 0);
    smb_message_destroy(msg);

    free(file->name);
    free(file);
}
Beispiel #5
0
smb_fd      smb_fopen(smb_session *s, smb_tid tid, const char *path,
                      uint32_t o_flags)
{
    smb_share       *share;
    smb_file        *file;
    smb_message     *req_msg, resp_msg;
    smb_create_req req;
    smb_create_resp *resp;
    size_t           path_len;
    int              res;
    char            *utf_path;

    assert(s != NULL && path != NULL);
    if ((share = smb_session_share_get(s, tid)) == NULL)
        return (0);

    path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path);
    if (path_len == 0)
        return (0);

    req_msg = smb_message_new(SMB_CMD_CREATE);
    if (!req_msg) {
        free(utf_path);
        return (0);
    }

    // Set SMB Headers
    req_msg->packet->header.tid = tid;

    // Create AndX Params
    SMB_MSG_INIT_PKT_ANDX(req);
    req.wct            = 24;
    req.flags          = 0;
    req.root_fid       = 0;
    req.access_mask    = o_flags;
    req.alloc_size     = 0;
    req.file_attr      = 0;
    req.share_access   = SMB_SHARE_READ | SMB_SHARE_WRITE;
    req.disposition    = 1;  // 1 = Open and file if doesn't exist
    req.create_opts    = 0;  // We dont't support create
    req.impersonation  = 2;  // ?????
    req.security_flags = 0;  // ???
    req.path_length    = path_len;
    req.bct            = path_len + 1;
    SMB_MSG_PUT_PKT(req_msg, req);

    // Create AndX 'Body'
    smb_message_put8(req_msg, 0);   // Align beginning of path
    smb_message_append(req_msg, utf_path, path_len);
    free(utf_path);

    // smb_message_put16(req_msg, 0);  // ??

    res = smb_session_send_msg(s, req_msg);
    smb_message_destroy(req_msg);
    if (!res)
        return (0);

    if (!smb_session_recv_msg(s, &resp_msg))
        return (0);
    if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
        return (0);

    resp = (smb_create_resp *)resp_msg.packet->payload;
    file = calloc(1, sizeof(smb_file));
    if (!file)
        return (0);

    file->fid           = resp->fid;
    file->tid           = tid;
    file->created       = resp->created;
    file->accessed      = resp->accessed;
    file->written       = resp->written;
    file->changed       = resp->changed;
    file->alloc_size    = resp->alloc_size;
    file->size          = resp->size;
    file->attr          = resp->attr;
    file->is_dir        = resp->is_dir;

    smb_session_file_add(s, tid, file); // XXX Check return

    return (SMB_FD(tid, file->fid));
}
Beispiel #6
0
static int      negotiate(smb_session *s, const char *domain)
{
    smb_message           *msg = NULL;
    smb_session_xsec_req  req;
    smb_buffer            ntlm;
    ASN1_TYPE             token;
    int                   res, der_size = 128;
    char                  der[128], err_desc[ASN1_MAX_ERROR_DESCRIPTION_SIZE];

    msg = smb_message_new(SMB_CMD_SETUP);
    if (!msg)
        return DSM_ERROR_GENERIC;

    // this struct will be set at the end when we know the payload size
    SMB_MSG_ADVANCE_PKT(msg, smb_session_xsec_req);

    asn1_create_element(s->spnego_asn1, "SPNEGO.GSSAPIContextToken", &token);

    res = asn1_write_value(token, "thisMech", spnego_oid, 1);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "spnego", "negTokenInit", 1);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "spnego.negTokenInit.mechTypes", "NEW", 1);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "spnego.negTokenInit.mechTypes.?1", ntlmssp_oid, 1);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "spnego.negTokenInit.reqFlags", NULL, 0);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "spnego.negTokenInit.mechListMIC", NULL, 0);
    if (res != ASN1_SUCCESS) goto error;

    smb_ntlmssp_negotiate(domain, domain, &ntlm);
    res = asn1_write_value(token, "spnego.negTokenInit.mechToken", ntlm.data,
                           ntlm.size);
    smb_buffer_free(&ntlm);
    if (res != ASN1_SUCCESS) goto error;

    res = asn1_der_coding(token, "", der, &der_size, err_desc);
    if (res != ASN1_SUCCESS)
    {
        smb_message_destroy(msg);
        BDSM_dbg("Encoding error: %s", err_desc);
        return DSM_ERROR_GENERIC;
    }

    smb_message_append(msg, der, der_size);
    smb_message_put_utf16(msg, SMB_OS, strlen(SMB_OS));
    smb_message_put16(msg, 0);
    smb_message_put_utf16(msg, SMB_LANMAN, strlen(SMB_LANMAN));
    smb_message_put16(msg, 0);
    smb_message_put16(msg, 0);

    SMB_MSG_INIT_PKT_ANDX(req);
    req.wct              = 12;
    req.max_buffer       = SMB_SESSION_MAX_BUFFER;
    req.mpx_count        = 16;
    req.vc_count         = 1;
    req.caps             = s->srv.caps;
    req.session_key      = s->srv.session_key;
    req.xsec_blob_size = der_size;
    req.payload_size   = msg->cursor - sizeof(smb_session_xsec_req);
    SMB_MSG_INSERT_PKT(msg, 0, req);

    asn1_delete_structure(&token);

    if (!smb_session_send_msg(s, msg))
    {
        smb_message_destroy(msg);
        BDSM_dbg("Unable to send Session Setup AndX (NTLMSSP_NEGOTIATE) message\n");
        return DSM_ERROR_NETWORK;
    }

    smb_message_destroy(msg);
    return DSM_SUCCESS;

error:
    asn1_display_error("smb_session_login negotiate()", res);
    smb_message_destroy(msg);
    return DSM_ERROR_GENERIC;
}
Beispiel #7
0
static int      auth(smb_session *s, const char *domain, const char *user,
                     const char *password)
{
    smb_message           *msg = NULL, resp;
    smb_session_xsec_req  req;
    smb_buffer            ntlm;
    ASN1_TYPE             token;
    int                   res, der_size = 512;
    char                  der[512], err_desc[ASN1_MAX_ERROR_DESCRIPTION_SIZE];

    msg = smb_message_new(SMB_CMD_SETUP);
    if (!msg)
        return DSM_ERROR_GENERIC;

    // this struct will be set at the end when we know the payload size
    SMB_MSG_ADVANCE_PKT(msg, smb_session_xsec_req);

    asn1_create_element(s->spnego_asn1, "SPNEGO.NegotiationToken", &token);

    // Select a response message type
    res = asn1_write_value(token, "", "negTokenResp", 1);
    if (res != ASN1_SUCCESS) goto error;

    // Delete all optionnal field except 'ResponseToken'
    res = asn1_write_value(token, "negTokenResp.negResult", NULL, 0);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "negTokenResp.supportedMech", NULL, 0);
    if (res != ASN1_SUCCESS) goto error;
    res = asn1_write_value(token, "negTokenResp.mechListMIC", NULL, 0);
    if (res != ASN1_SUCCESS) goto error;


    smb_ntlmssp_response(s->srv.challenge, s->srv.ts - 4200, domain, domain, user,
                         password, &s->xsec_target, &ntlm);
    res = asn1_write_value(token, "negTokenResp.responseToken", ntlm.data,
                           ntlm.size);
    smb_buffer_free(&ntlm);
    if (res != ASN1_SUCCESS) goto error;

    res = asn1_der_coding(token, "", der, &der_size, err_desc);
    if (res != ASN1_SUCCESS)
    {
        smb_message_destroy(msg);
        BDSM_dbg("Encoding error: %s", err_desc);
        return DSM_ERROR_GENERIC;
    }

    smb_message_append(msg, der, der_size);
    if (msg->cursor % 2)
        smb_message_put8(msg, 0);
    smb_message_put_utf16(msg, SMB_OS, strlen(SMB_OS));
    smb_message_put16(msg, 0);
    smb_message_put_utf16(msg, SMB_LANMAN, strlen(SMB_LANMAN));
    smb_message_put16(msg, 0);
    smb_message_put16(msg, 0); // Empty PDC name

    SMB_MSG_INIT_PKT_ANDX(req);
    req.wct              = 12;
    req.max_buffer       = SMB_SESSION_MAX_BUFFER;
    req.mpx_count        = 16; // XXX ?
    req.vc_count         = 1;
    req.caps             = s->srv.caps; // XXX caps & our_caps_mask
    req.session_key      = s->srv.session_key;
    req.xsec_blob_size = der_size;
    req.payload_size   = msg->cursor - sizeof(smb_session_xsec_req);
    SMB_MSG_INSERT_PKT(msg, 0, req);

    asn1_delete_structure(&token);

    if (!smb_session_send_msg(s, msg))
    {
        smb_message_destroy(msg);
        BDSM_dbg("Unable to send Session Setup AndX (NTLMSSP_AUTH) message\n");
        return DSM_ERROR_NETWORK;
    }
    smb_message_destroy(msg);

    if (smb_session_recv_msg(s, &resp) == 0)
        return DSM_ERROR_NETWORK;

    if (!smb_session_check_nt_status(s, &resp))
        return DSM_ERROR_NT;
    else
    {
        smb_session_xsec_resp *r = (smb_session_xsec_resp *)resp.packet->payload;
        if (r->action & 0x0001)
            s->guest = true;

        s->srv.uid  = resp.packet->header.uid;
        s->logged = true;

        return DSM_SUCCESS;
    }

error:
    asn1_display_error("smb_session_login auth()", res);
    smb_message_destroy(msg);
    return DSM_ERROR_GENERIC;
}
Beispiel #8
0
smb_file  *smb_fstat(smb_session *s, smb_tid tid, const char *path)
{
  smb_message           *msg, reply;
  smb_trans2_req        *tr2;
  smb_trans2_resp       *tr2_resp;
  smb_tr2_query         *query;
  smb_tr2_path_info     *info;
  smb_file              *file;
  size_t                path_len, msg_len;
  int                   res;

  assert(s != NULL && path != NULL && tid);

  path_len  = strlen(path) + 1;
  msg_len   = sizeof(smb_trans2_req) + sizeof(smb_tr2_query);
  msg_len  += path_len * 2 + 3; // +3 for eventual padding

  msg = smb_message_new(SMB_CMD_TRANS2, msg_len);
  smb_message_set_default_flags(msg);
  msg->packet->header.tid = tid;

  tr2 = (smb_trans2_req *)msg->packet->payload;
  tr2->wct                = 15;
  tr2->total_param_count  = path_len * 2 + sizeof(smb_tr2_query);
  tr2->max_param_count    = 2; // ?? Why not the same or 12 ?
  tr2->max_data_count     = 0xffff;
  tr2->param_count        = tr2->total_param_count;
  tr2->param_offset       = 68; // Offset of find_first_params in packet;
  tr2->data_count         = 0;
  tr2->data_offset        = 96; // Offset of pattern in packet
  tr2->setup_count        = 1;
  tr2->cmd                = SMB_TR2_QUERY_PATH;
  tr2->bct                = sizeof(smb_tr2_query) + path_len * 2 + 3;

  query = (smb_tr2_query *)tr2->payload;
  query->interest   = 0x0107;   // Query File All Info

  smb_message_advance(msg, sizeof(smb_trans2_req));
  smb_message_advance(msg, sizeof(smb_tr2_query));
  smb_message_put_utf16(msg, "", path, path_len);

  // Adds padding at the end if necessary.
  if (msg->cursor % 4)
  {
    int padding = 4 - msg->cursor % 4;
    tr2->bct += padding;
    for (int i = 0; i < padding; i++)
      smb_message_put8(msg, 0);
  }

  res = smb_session_send_msg(s, msg);
  smb_message_destroy(msg);
  if (!res)
  {
    BDSM_dbg("Unable to query pattern: %s\n", path);
    return (NULL);
  }

  if (!smb_session_recv_msg(s, &reply)
      || reply.packet->header.status != NT_STATUS_SUCCESS)
  {
    BDSM_dbg("Unable to recv msg or failure for %s\n", path);
    return (NULL);
  }

  tr2_resp  = (smb_trans2_resp *)reply.packet->payload;
  info      = (smb_tr2_path_info *)(tr2_resp->payload + 4); //+4 is padding
  file      = calloc(1, sizeof(smb_file));
  assert(file != NULL);

  file->name_len  = smb_from_utf16((const char *)info->name, info->name_len,
                                  &file->name);
  file->name[info->name_len] = 0;

  file->created     = info->created;
  file->accessed    = info->accessed;
  file->written     = info->written;
  file->changed     = info->changed;
  file->alloc_size  = info->alloc_size;
  file->size        = info->size;
  file->attr        = info->attr;
  file->is_dir      = info->is_dir;

  return (file);
}
Beispiel #9
0
int smb_tree_connect(smb_session *s, const char *name, smb_tid *tid)
{
    smb_tree_connect_req  req;
    smb_tree_connect_resp *resp;
    smb_message            resp_msg;
    smb_message           *req_msg;
    smb_share             *share;
    size_t                 path_len, utf_path_len;
    char                  *path, *utf_path;

    assert(s != NULL && name != NULL && tid != NULL);

    if( s != NULL && name != NULL && tid != NULL ) {

        req_msg = smb_message_new(SMB_CMD_TREE_CONNECT);
        if (!req_msg)
            return DSM_ERROR_GENERIC;

        // Build \\SERVER\Share path from name
        path_len  = strlen(name) + strlen(s->srv.name) + 4;
        path      = alloca(path_len);
        snprintf(path, path_len, "\\\\%s\\%s", s->srv.name, name);
        utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path);

        // Packet headers
        req_msg->packet->header.tid   = 0xffff; // Behavior of libsmbclient

        smb_message_set_andx_members(req_msg);

        // Packet payload
        SMB_MSG_INIT_PKT_ANDX(req);
        req.wct          = 4;
        req.flags        = 0x0c; // (??)
        req.passwd_len   = 1;    // Null byte
        req.bct = utf_path_len + 6 + 1;
        SMB_MSG_PUT_PKT(req_msg, req);

        smb_message_put8(req_msg, 0); // Ze null byte password;
        smb_message_append(req_msg, utf_path, utf_path_len);
        free(utf_path);
        smb_message_append(req_msg, "?????", strlen("?????") + 1);

        if (!smb_session_send_msg(s, req_msg))
        {
            smb_message_destroy(req_msg);
            return DSM_ERROR_NETWORK;
        }
        smb_message_destroy(req_msg);

        if (!smb_session_recv_msg(s, &resp_msg))
            return DSM_ERROR_NETWORK;

        if (!smb_session_check_nt_status(s, &resp_msg))
            return DSM_ERROR_NT;

        resp  = (smb_tree_connect_resp *)resp_msg.packet->payload;
        share = calloc(1, sizeof(smb_share));
        if (!share)
            return DSM_ERROR_GENERIC;

        share->tid          = resp_msg.packet->header.tid;
        share->opts         = resp->opt_support;
        share->rights       = resp->max_rights;
        share->guest_rights = resp->guest_rights;

        smb_session_share_add(s, share);

        *tid = share->tid;
        return 0;
    }

    return DSM_ERROR_GENERIC;
}
Beispiel #10
0
// We should normally implement SCERPC and SRVSVC to perform a share list. But
// since these two protocols have no other use for us, we'll do it the trash way
// PS: Worst function _EVER_. I don't understand a bit myself
int             smb_share_get_list(smb_session *s, smb_share_list *list, size_t *pcount)
{
    smb_message           *req, resp;
    smb_trans_req         trans;
    smb_tid               ipc_tid;
    smb_fd                srvscv_fd;
    uint16_t              rpc_len;
    size_t                res, frag_len_cursor;
    ssize_t               count;
    int                   ret;

    assert(s != NULL && list != NULL);

    if(s != NULL && list != NULL) {

        *list = NULL;

        if ((ret = smb_tree_connect(s, "IPC$", &ipc_tid)) != DSM_SUCCESS)
            return ret;

        if ((ret = smb_fopen(s, ipc_tid, "\\srvsvc", SMB_MOD_READ | SMB_MOD_WRITE,
                             &srvscv_fd)) != DSM_SUCCESS)
            return ret;

        //// Phase 1:
        // We bind a context or whatever for DCE/RPC

        req = smb_message_new(SMD_CMD_TRANS);
        if (!req)
        {
            ret = DSM_ERROR_GENERIC;
            goto error;
        }
        req->packet->header.tid = ipc_tid;

        rpc_len = 0xffff;
        SMB_MSG_INIT_PKT(trans);
        trans.wct                    = 16;
        trans.total_data_count       = 72;
        trans.max_data_count         = rpc_len;
        trans.param_offset           = 84;
        trans.data_count             = 72;
        trans.data_offset            = 84;
        trans.setup_count            = 2;
        trans.pipe_function          = 0x26;
        trans.fid                    = SMB_FD_FID(srvscv_fd);
        trans.bct                    = 89;
        SMB_MSG_PUT_PKT(req, trans);

        smb_message_put8(req, 0);   // Padding
        smb_message_put_utf16(req, "\\PIPE\\", strlen("\\PIPE\\") + 1);
        smb_message_put16(req, 0);  // Padding to be aligned with wtf boundary :-/

        // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
        // from wireshark values.
        smb_message_put8(req, 5);     // version major
        smb_message_put8(req, 0);     // minor
        smb_message_put8(req, 0x0b);  // Packet type = 'bind'
        smb_message_put8(req, 0x03);  // Packet flags = ??
        smb_message_put32(req, 0x10); // Representation = little endian/ASCII. Damn
        smb_message_put16(req, 72);   // Data len again
        smb_message_put16(req, 0);    // Auth len ?
        smb_message_put32(req, 19);   // Call ID ?
        smb_message_put16(req, rpc_len);      // Max Xmit size
        smb_message_put16(req, rpc_len);      // Max Recv size
        smb_message_put32(req, 0);    // Assoc group ?

        smb_message_put32(req, 1);    // Num Ctx Item
        // Adding the CtxItem, whatever could that be
        smb_message_put16(req, 0);    // ContextID
        smb_message_put16(req, 1);    // Num Trans Item
        // SRVSVC UUID
        const uint8_t uuid_e[8] = {0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88};
        smb_message_put_uuid(req, 0x4b324fc8, 0x1670, 0x01d3, uuid_e);
        smb_message_put16(req, 3);    // Version
        smb_message_put16(req, 0);    // Minor
        // Another UUID
        const uint8_t uuid_e2[8] = {0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60};
        smb_message_put_uuid(req, 0x8a885d04, 0x1ceb, 0x11c9, uuid_e2);
        smb_message_put32(req, 2);    // Another version

        // Let's send this ugly pile of shit over the network !
        res = smb_session_send_msg(s, req);
        smb_message_destroy(req);
        if (!res)
        {
            ret = DSM_ERROR_NETWORK;
            goto error;
        }

        // Is the server throwing pile of shit back at me ?
        res = smb_session_recv_msg(s, &resp);
        if (!res || resp.packet->payload[68])
        {
            BDSM_dbg("Bind call failed: 0x%hhx (reason = 0x%hhx)\n",
                     resp.packet->payload[68], resp.packet->payload[70]);
            ret = DSM_ERROR_NETWORK;
            goto error;
        }


        //// Phase 2:
        // Now we have the 'bind' done (regarless of what it is), we'll call
        // NetShareEnumAll

        req = smb_message_new(SMD_CMD_TRANS);
        if (!req)
        {
            ret = DSM_ERROR_GENERIC;
            goto error;
        }
        req->packet->header.tid = ipc_tid;

        // this struct will be set at the end when we know the data size
        SMB_MSG_ADVANCE_PKT(req, smb_trans_req);

        smb_message_put8(req, 0);  // Padding
        smb_message_put_utf16(req, "\\PIPE\\", strlen("\\PIPE\\") + 1);
        smb_message_put16(req, 0); // Padding

        // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
        // from wireshark values.
        smb_message_put8(req, 5);     // version major
        smb_message_put8(req, 0);     // minor
        smb_message_put8(req, 0);     // Packet type = 'request'
        smb_message_put8(req, 0x03);  // Packet flags = ??
        smb_message_put32(req, 0x10); // Representation = little endian/ASCII. Damn
        // Let's save the cursor here to update that later
        frag_len_cursor = req->cursor;
        smb_message_put16(req, 0);    // Data len again (frag length)
        smb_message_put16(req, 0);    // Auth len ?
        smb_message_put32(req, 12);   // Call ID ?
        smb_message_put32(req, 64);   // Alloc hint ?
        smb_message_put16(req, 0);    // Context ID ?
        smb_message_put16(req, 15);   // OpNum = NetShareEnumAll

        // Pointer to server UNC
        smb_message_put32(req, 0x00020000);   // Referent ID ?
        smb_message_put32(req, strlen(s->srv.name) + 1);            // Max count
        smb_message_put32(req, 0);            // Offset
        smb_message_put32(req, strlen(s->srv.name) + 1);            // Actual count
        // The server name, supposed to be downcased
        smb_message_put_utf16(req, s->srv.name, strlen(s->srv.name) + 1);
        if ((strlen(s->srv.name) % 2) == 0) // It won't be aligned with the terminating byte
            smb_message_put16(req, 0);

        smb_message_put32(req, 1);            // Level 1 ?
        smb_message_put32(req, 1);            // Ctr ?
        smb_message_put32(req, 0x00020004);   // Referent ID ?
        smb_message_put64(req, 0);            // Count/Null Pointer to NetShareInfo1
        smb_message_put32(req, 0xffffffff);   // Max Buffer (0xffffffff required by smbX)

        smb_message_put32(req, 0x00020008);   // Referent ID ?
        smb_message_put32(req, 0);            // Resume ?

        // fill trans pkt at the end since we know the size at the end
        SMB_MSG_INIT_PKT(trans);
        trans.wct              = 16;
        trans.max_data_count   = 4280;
        trans.setup_count      = 2;
        trans.pipe_function    = 0x26; // TransactNmPipe;
        trans.fid              = SMB_FD_FID(srvscv_fd);
        trans.bct              = req->cursor - sizeof(smb_trans_req);
        trans.data_count       = trans.bct - 17; // 17 -> padding + \PIPE\ + padding
        trans.total_data_count = trans.data_count;
        trans.data_offset      = 84;
        trans.param_offset     = 84;
        // but insert it at the begining
        SMB_MSG_INSERT_PKT(req, 0, trans);

        req->packet->payload[frag_len_cursor] = trans.data_count; // (data_count SHOULD stay < 256)

        // Let's send this ugly pile of shit over the network !
        res = smb_session_send_msg(s, req);
        smb_message_destroy(req);
        if (!res)
        {
            ret = DSM_ERROR_NETWORK;
            goto error;
        }

        // Is the server throwing pile of shit back at me ?
        res = smb_session_recv_msg(s, &resp);
        if (!res && (uint32_t)resp.packet->payload[resp.payload_size - 4])
        {
            BDSM_dbg("NetShareEnumAll call failed.\n");
            ret = DSM_ERROR_NETWORK;
            goto error;
        }


        //// Phase 3
        // We parse the list of Share (finally !) and build function response
        count = smb_share_parse_enum(&resp, list);
        if (count == -1)
        {
            ret = DSM_ERROR_GENERIC;
            goto error;
        }
        if (pcount != NULL)
            *pcount = count;
        ret = DSM_SUCCESS;

error:
        // Close the pipe
        smb_fclose(s, srvscv_fd);
        return ret;
    }

    ret = DSM_ERROR_GENERIC;
}
Beispiel #11
0
smb_file  *smb_fstat(smb_session *s, smb_tid tid, const char *path)
{
    smb_message           *msg, reply;
    smb_trans2_req        tr2;
    smb_trans2_resp       *tr2_resp;
    smb_tr2_query         query;
    smb_tr2_path_info     *info;
    smb_file              *file;
    size_t                utf_path_len, msg_len;
    char                  *utf_path;
    int                   res, padding = 0;

    assert(s != NULL && path != NULL);

    utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path);
    if (utf_path_len == 0)
        return 0;

    msg_len   = sizeof(smb_trans2_req) + sizeof(smb_tr2_query);
    msg_len  += utf_path_len;
    if (msg_len %4)
        padding = 4 - msg_len % 4;

    msg = smb_message_new(SMB_CMD_TRANS2);
    if (!msg) {
        free(utf_path);
        return 0;
    }
    msg->packet->header.tid = tid;

    SMB_MSG_INIT_PKT(tr2);
    tr2.wct                = 15;
    tr2.total_param_count  = utf_path_len + sizeof(smb_tr2_query);
    tr2.param_count        = tr2.total_param_count;
    tr2.max_param_count    = 2; // ?? Why not the same or 12 ?
    tr2.max_data_count     = 0xffff;
    tr2.param_offset       = 68; // Offset of find_first_params in packet;
    tr2.data_count         = 0;
    tr2.data_offset        = 96; // Offset of pattern in packet
    tr2.setup_count        = 1;
    tr2.cmd                = SMB_TR2_QUERY_PATH;
    tr2.bct                = sizeof(smb_tr2_query) + utf_path_len + padding;
    SMB_MSG_PUT_PKT(msg, tr2);

    SMB_MSG_INIT_PKT(query);
    query.interest   = SMB_FIND2_QUERY_FILE_ALL_INFO;
    SMB_MSG_PUT_PKT(msg, query);

    smb_message_append(msg, utf_path, utf_path_len);
    free(utf_path);

    // Adds padding at the end if necessary.
    while (padding--)
        smb_message_put8(msg, 0);

    res = smb_session_send_msg(s, msg);
    smb_message_destroy(msg);
    if (!res)
    {
        BDSM_dbg("Unable to query pattern: %s\n", path);
        return NULL;
    }

    if (!smb_session_recv_msg(s, &reply)
        || reply.packet->header.status != NT_STATUS_SUCCESS)
    {
        BDSM_dbg("Unable to recv msg or failure for %s\n", path);
        return NULL;
    }

    tr2_resp  = (smb_trans2_resp *)reply.packet->payload;
    info      = (smb_tr2_path_info *)(tr2_resp->payload + 4); //+4 is padding
    file      = calloc(1, sizeof(smb_file));
    if (!file)
        return NULL;

    file->name_len  = smb_from_utf16((const char *)info->name, info->name_len,
                                     &file->name);
    file->name[info->name_len / 2] = 0;

    file->created     = info->created;
    file->accessed    = info->accessed;
    file->written     = info->written;
    file->changed     = info->changed;
    file->alloc_size  = info->alloc_size;
    file->size        = info->size;
    file->attr        = info->attr;
    file->is_dir      = info->is_dir;

    return file;
}
Beispiel #12
0
static smb_message  *smb_trans2_find_next (smb_session *s, smb_tid tid, uint16_t resume_key, uint16_t sid, const char *pattern)
{
    smb_message           *msg_find_next2 = NULL;
    smb_trans2_req        tr2_find_next2;
    smb_tr2_findnext2     find_next2;
    size_t                utf_pattern_len, tr2_bct, tr2_param_count;
    char                  *utf_pattern;
    int                   res;
    unsigned int          padding = 0;

    assert(s != NULL && pattern != NULL);

    utf_pattern_len = smb_to_utf16(pattern, strlen(pattern) + 1, &utf_pattern);
    if (utf_pattern_len == 0)
        return NULL;

    tr2_bct = sizeof(smb_tr2_findnext2) + utf_pattern_len;
    tr2_param_count = tr2_bct;
    tr2_bct += 3;
    // Adds padding at the end if necessary.
    while ((tr2_bct % 4) != 3)
    {
        padding++;
        tr2_bct++;
    }

    msg_find_next2 = smb_message_new(SMB_CMD_TRANS2);
    if (!msg_find_next2)
    {
        free(utf_pattern);
        return NULL;
    }
    msg_find_next2->packet->header.tid = tid;

    SMB_MSG_INIT_PKT(tr2_find_next2);
    tr2_find_next2.wct                = 0x0f;
    tr2_find_next2.total_param_count  = tr2_param_count;
    tr2_find_next2.total_data_count   = 0x0000;
    tr2_find_next2.max_param_count    = 10; // ?? Why not the same or 12 ?
    tr2_find_next2.max_data_count     = 0xffff;
    //max_setup_count
    //reserved
    //flags
    //timeout
    //reserve2
    tr2_find_next2.param_count        = tr2_param_count;
    tr2_find_next2.param_offset       = 68; // Offset of find_next_params in packet;
    tr2_find_next2.data_count         = 0;
    tr2_find_next2.data_offset        = 88; // Offset of pattern in packet
    tr2_find_next2.setup_count        = 1;
    //reserve3
    tr2_find_next2.cmd                = SMB_TR2_FIND_NEXT;
    tr2_find_next2.bct = tr2_bct; //3 == padding
    SMB_MSG_PUT_PKT(msg_find_next2, tr2_find_next2);

    SMB_MSG_INIT_PKT(find_next2);
    find_next2.sid        = sid;
    find_next2.count      = 255;
    find_next2.interest   = SMB_FIND2_INTEREST_BOTH_DIRECTORY_INFO;
    find_next2.flags      = SMB_FIND2_FLAG_CLOSE_EOS|SMB_FIND2_FLAG_CONTINUE;
    find_next2.resume_key = resume_key;
    SMB_MSG_PUT_PKT(msg_find_next2, find_next2);
    smb_message_append(msg_find_next2, utf_pattern, utf_pattern_len);
    while (padding--)
        smb_message_put8(msg_find_next2, 0);

    res = smb_session_send_msg(s, msg_find_next2);
    smb_message_destroy(msg_find_next2);
    free(utf_pattern);

    if (!res)
    {
        BDSM_dbg("Unable to query pattern: %s\n", pattern);
        return NULL;
    }

    msg_find_next2 = smb_tr2_recv(s);
    return msg_find_next2;
}
Beispiel #13
0
static smb_message  *smb_trans2_find_first (smb_session *s, smb_tid tid, const char *pattern)
{
    smb_message           *msg;
    smb_trans2_req        tr2;
    smb_tr2_findfirst2    find;
    size_t                utf_pattern_len, tr2_bct, tr2_param_count;
    char                  *utf_pattern;
    int                   res;
    unsigned int          padding = 0;

    assert(s != NULL && pattern != NULL);

    utf_pattern_len = smb_to_utf16(pattern, strlen(pattern) + 1, &utf_pattern);
    if (utf_pattern_len == 0)
        return NULL;

    tr2_bct = sizeof(smb_tr2_findfirst2) + utf_pattern_len;
    tr2_param_count = tr2_bct;
    tr2_bct += 3;
    // Adds padding at the end if necessary.
    while ((tr2_bct % 4) != 3)
    {
        padding++;
        tr2_bct++;
    }

    msg = smb_message_new(SMB_CMD_TRANS2);
    if (!msg) {
        free(utf_pattern);
        return NULL;
    }
    msg->packet->header.tid = tid;

    SMB_MSG_INIT_PKT(tr2);
    tr2.wct                = 15;
    tr2.max_param_count    = 10; // ?? Why not the same or 12 ?
    tr2.max_data_count     = 0xffff;;
    tr2.param_offset       = 68; // Offset of find_first_params in packet;
    tr2.data_count         = 0;
    tr2.data_offset        = 88; // Offset of pattern in packet
    tr2.setup_count        = 1;
    tr2.cmd                = SMB_TR2_FIND_FIRST;
    tr2.total_param_count = tr2_param_count;
    tr2.param_count       = tr2_param_count;
    tr2.bct = tr2_bct; //3 == padding
    SMB_MSG_PUT_PKT(msg, tr2);

    SMB_MSG_INIT_PKT(find);
    find.attrs     = SMB_FIND2_ATTR_DEFAULT;
    find.count     = 1366;     // ??
    find.flags     = SMB_FIND2_FLAG_CLOSE_EOS | SMB_FIND2_FLAG_RESUME;
    find.interest  = SMB_FIND2_INTEREST_BOTH_DIRECTORY_INFO;
    SMB_MSG_PUT_PKT(msg, find);
    smb_message_append(msg, utf_pattern, utf_pattern_len);
    while (padding--)
        smb_message_put8(msg, 0);

    res = smb_session_send_msg(s, msg);
    smb_message_destroy(msg);
    free(utf_pattern);

    if (!res)
    {
        BDSM_dbg("Unable to query pattern: %s\n", pattern);
        return NULL;
    }

    msg = smb_tr2_recv(s);
    return msg;
}