예제 #1
0
/*
 * Convert an SMB error into a UNIX error ...
 */
int
SMBC_errno(SMBCCTX *context,
           struct cli_state *c)
{
	int ret = cli_errno(c);

        if (cli_is_dos_error(c)) {
                uint8 eclass;
                uint32 ecode;

                cli_dos_error(c, &eclass, &ecode);

                DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
                         (int)eclass, (int)ecode, (int)ecode, ret));
        } else {
                NTSTATUS status;

                status = cli_nt_error(c);

                DEBUG(3,("smbc errno %s -> %d\n",
                         nt_errstr(status), ret));
        }

	return ret;
}
예제 #2
0
파일: clierror.c 프로젝트: AIdrifter/samba
int cli_errno(struct cli_state *cli)
{
	NTSTATUS status;

	if (cli_is_nt_error(cli)) {
		status = cli_nt_error(cli);
		return map_errno_from_nt_status(status);
	}

        if (cli_is_dos_error(cli)) {
                uint8 eclass;
                uint32 ecode;

                cli_dos_error(cli, &eclass, &ecode);
		status = dos_to_ntstatus(eclass, ecode);
		return map_errno_from_nt_status(status);
        }

        /*
         * Yuck!  A special case for this Vista error.  Since its high-order
         * byte isn't 0xc0, it doesn't match cli_is_nt_error() above.
         */
        status = cli_nt_error(cli);
        if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
            return EACCES;
        }

	/* for other cases */
	return EINVAL;
}
예제 #3
0
파일: clirap.c 프로젝트: aosm/samba
NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
{
	unsigned int data_len = 0;
	unsigned int param_len = 0;
	uint16 setup = TRANSACT2_QPATHINFO;
	pstring param;
	char *rparam=NULL, *rdata=NULL;
	int count=8;
	char *p;
	BOOL ret;
	unsigned int len;

	p = param;
	memset(p, 0, 6);
	SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
	p += 6;
	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);

	param_len = PTR_DIFF(p, param);

	do {
		ret = (cli_send_trans(cli, SMBtrans2, 
				      NULL,           /* Name */
				      -1, 0,          /* fid, flags */
				      &setup, 1, 0,   /* setup, length, max */
				      param, param_len, 10, /* param, length, max */
				      NULL, data_len, cli->max_xmit /* data, length, max */
				      ) &&
		       cli_receive_trans(cli, SMBtrans2, 
					 &rparam, &param_len,
					 &rdata, &data_len));
		if (!ret && cli_is_dos_error(cli)) {
			/* we need to work around a Win95 bug - sometimes
			   it gives ERRSRV/ERRerror temprarily */
			uint8 eclass;
			uint32 ecode;
			cli_dos_error(cli, &eclass, &ecode);
			if (eclass != ERRSRV || ecode != ERRerror) break;
			smb_msleep(100);
		}
	} while (count-- && ret==False);

	if (!ret || !rdata || data_len < 4) {
		return NT_STATUS_UNSUCCESSFUL;
	}

	len = IVAL(rdata, 0);

	if (len > data_len - 4) {
		return NT_STATUS_INVALID_NETWORK_RESPONSE;
	}

	clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);

	SAFE_FREE(rdata);
	SAFE_FREE(rparam);

	return NT_STATUS_OK;
}
예제 #4
0
NTSTATUS cli_get_nt_error(struct cli_state *cli)
{
    if (cli_is_nt_error(cli)) {
        return cli_nt_error(cli);
    } else if (cli_is_dos_error(cli)) {
        uint32 ecode;
        uint8 eclass;
        cli_dos_error(cli, &eclass, &ecode);
        return dos_to_ntstatus(eclass, ecode);
    } else {
        /* Something went wrong, we don't know what. */
        return NT_STATUS_UNSUCCESSFUL;
    }
}
예제 #5
0
파일: clierror.c 프로젝트: jophxy/samba
const char *cli_errstr(struct cli_state *cli)
{   
	static fstring cli_error_message;
	uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
        uint8 errclass;
        int i;
	
	if (!cli->initialised) {
		fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
		return cli_error_message;
	}
		
	/* Was it server socket error ? */
	if (cli->fd == -1 && cli->smb_rw_error) {
		switch(cli->smb_rw_error) {
			case READ_TIMEOUT:
				slprintf(cli_error_message, sizeof(cli_error_message) - 1,
					"Call timed out: server did not respond after %d milliseconds", 
					cli->timeout);
				break;
			case READ_EOF:
				slprintf(cli_error_message, sizeof(cli_error_message) - 1,
					"Call returned zero bytes (EOF)\n" );
				break;
			case READ_ERROR:
				slprintf(cli_error_message, sizeof(cli_error_message) - 1,
					"Read error: %s\n", strerror(errno) );
				break;
			case WRITE_ERROR:
				slprintf(cli_error_message, sizeof(cli_error_message) - 1,
					"Write error: %s\n", strerror(errno) );
				break;
			default:
				slprintf(cli_error_message, sizeof(cli_error_message) - 1,
					"Unknown error code %d\n", cli->smb_rw_error );
				break;
		}
		return cli_error_message;
	}

        /* Case #1: RAP error */
	if (cli->rap_error) {
		for (i = 0; rap_errmap[i].message != NULL; i++) {
			if (rap_errmap[i].err == cli->rap_error) {
				return rap_errmap[i].message;
			}
		} 

		slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d", 
			cli->rap_error);

		return cli_error_message;
	}

        /* Case #2: 32-bit NT errors */
	if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
                NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));

                return get_nt_error_msg(status);
        }

        cli_dos_error(cli, &errclass, &errnum);

        /* Case #3: SMB error */

	return cli_smb_errstr(cli);
}
예제 #6
0
파일: clilist.c 프로젝트: AllardJ/Tomato
int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, 
		 void (*fn)(const char *, file_info *, const char *, void *), void *state)
{
#if 1
	int max_matches = 1366; /* Match W2k - was 512. */
#else
	int max_matches = 512;
#endif
	int info_level;
	char *p, *p2;
	pstring mask;
	file_info finfo;
	int i;
	char *dirlist = NULL;
	int dirlist_len = 0;
	int total_received = -1;
	BOOL First = True;
	int ff_searchcount=0;
	int ff_eos=0;
	int ff_dir_handle=0;
	int loop_count = 0;
	char *rparam=NULL, *rdata=NULL;
	unsigned int param_len, data_len;	
	uint16 setup;
	pstring param;
	const char *mnt;
	uint32 resume_key = 0;
	uint32 last_name_raw_len = 0;
	DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));

	/* NT uses 260, OS/2 uses 2. Both accept 1. */
	info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
	
	pstrcpy(mask,Mask);
	
	while (ff_eos == 0) {
		loop_count++;
		if (loop_count > 200) {
			DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
			break;
		}

		if (First) {
			setup = TRANSACT2_FINDFIRST;
			SSVAL(param,0,attribute); /* attribute */
			SSVAL(param,2,max_matches); /* max count */
			SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));	/* resume required + close on end */
			SSVAL(param,6,info_level); 
			SIVAL(param,8,0);
			p = param+12;
			p += clistr_push(cli, param+12, mask, sizeof(param)-12, 
					 STR_TERMINATE);
		} else {
			setup = TRANSACT2_FINDNEXT;
			SSVAL(param,0,ff_dir_handle);
			SSVAL(param,2,max_matches); /* max count */
			SSVAL(param,4,info_level); 
			/* For W2K servers serving out FAT filesystems we *must* set the
			   resume key. If it's not FAT then it's returned as zero. */
			SIVAL(param,6,resume_key); /* ff_resume_key */
			/* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren
			   can miss filenames. Use last filename continue instead. JRA */
			SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));	/* resume required + close on end */
			p = param+12;
			if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
				memcpy(p, last_name_raw.data, last_name_raw_len);
				p += last_name_raw_len;
			} else {
				p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
			}
		}

		param_len = PTR_DIFF(p, param);

		if (!cli_send_trans(cli, SMBtrans2, 
				    NULL,                   /* Name */
				    -1, 0,                  /* fid, flags */
				    &setup, 1, 0,           /* setup, length, max */
				    param, param_len, 10,   /* param, length, max */
				    NULL, 0, 
#if 0
				    /* w2k value. */
				    MIN(16384,cli->max_xmit) /* data, length, max. */
#else
				    cli->max_xmit	    /* data, length, max. */
#endif
				    )) {
			break;
		}

		if (!cli_receive_trans(cli, SMBtrans2, 
				       &rparam, &param_len,
				       &rdata, &data_len) &&
                    cli_is_dos_error(cli)) {
			/* We need to work around a Win95 bug - sometimes
			   it gives ERRSRV/ERRerror temprarily */
			uint8 eclass;
			uint32 ecode;

			SAFE_FREE(rdata);
			SAFE_FREE(rparam);

			cli_dos_error(cli, &eclass, &ecode);

			/*
			 * OS/2 might return "no more files",
			 * which just tells us, that searchcount is zero
			 * in this search.
			 * Guenter Kukkukk <*****@*****.**>
			 */

			if (eclass == ERRDOS && ecode == ERRnofiles) {
				ff_searchcount = 0;
				cli_reset_error(cli);
				break;
			}

			if (eclass != ERRSRV || ecode != ERRerror)
				break;
			smb_msleep(100);
			continue;
		}

                if (cli_is_error(cli) || !rdata || !rparam) {
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		if (total_received == -1)
			total_received = 0;

		/* parse out some important return info */
		p = rparam;
		if (First) {
			ff_dir_handle = SVAL(p,0);
			ff_searchcount = SVAL(p,2);
			ff_eos = SVAL(p,4);
		} else {
			ff_searchcount = SVAL(p,0);
			ff_eos = SVAL(p,2);
		}

		if (ff_searchcount == 0) {
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		/* point to the data bytes */
		p = rdata;

		/* we might need the lastname for continuations */
		for (p2=p,i=0;i<ff_searchcount;i++) {
			if ((info_level == 260) && (i == ff_searchcount-1)) {
				/* Last entry - fixup the last offset length. */
				SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
			}
			p2 += interpret_long_filename(cli,info_level,p2,&finfo,
							&resume_key,&last_name_raw,&last_name_raw_len);

			if (!First && *mask && strcsequal(finfo.name, mask)) {
				DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
					finfo.name));
				ff_eos = 1;
				break;
			}
		}

		if (ff_searchcount > 0) {
			pstrcpy(mask, finfo.name);
		} else {
			pstrcpy(mask,"");
		}

		/* grab the data for later use */
		/* and add them to the dirlist pool */
		dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);

		if (!dirlist) {
			DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		memcpy(dirlist+dirlist_len,p,data_len);
		dirlist_len += data_len;

		total_received += ff_searchcount;

		SAFE_FREE(rdata);
		SAFE_FREE(rparam);

		DEBUG(3,("received %d entries (eos=%d)\n",
			 ff_searchcount,ff_eos));

		if (ff_searchcount > 0)
			loop_count = 0;

		First = False;
	}

	mnt = cli_cm_get_mntpoint( cli );

        /* see if the server disconnected or the connection otherwise failed */
        if (cli_is_error(cli)) {
                total_received = -1;
        } else {
                /* no connection problem.  let user function add each entry */
                for (p=dirlist,i=0;i<total_received;i++) {
                        p += interpret_long_filename(cli, info_level, p,
                                                     &finfo,NULL,NULL,NULL);
                        fn( mnt,&finfo, Mask, state );
                }
        }

	/* free up the dirlist buffer and last name raw blob */
	SAFE_FREE(dirlist);
	data_blob_free(&last_name_raw);
	return(total_received);
}
예제 #7
0
파일: clirap.c 프로젝트: aosm/samba
BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, 
                     time_t create_time,
                     time_t access_time,
                     time_t write_time,
                     time_t change_time,
                     uint16 mode)
{
	unsigned int data_len = 0;
	unsigned int param_len = 0;
	unsigned int rparam_len, rdata_len;
	uint16 setup = TRANSACT2_SETPATHINFO;
	pstring param;
        pstring data;
	char *rparam=NULL, *rdata=NULL;
	int count=8;
	BOOL ret;
	char *p;

	memset(param, 0, sizeof(param));
	memset(data, 0, sizeof(data));

        p = param;

        /* Add the information level */
	SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);

        /* Skip reserved */
	p += 6;

        /* Add the file name */
	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);

	param_len = PTR_DIFF(p, param);

        p = data;

        /*
         * Add the create, last access, modification, and status change times
         */
        
        put_long_date(p, create_time);
        p += 8;

        put_long_date(p, access_time);
        p += 8;
        
        put_long_date(p, write_time);
        p += 8;
        
        put_long_date(p, change_time);
        p += 8;

        /* Add attributes */
        SIVAL(p, 0, mode);
        p += 4;

        /* Add padding */
        SIVAL(p, 0, 0);
        p += 4;

        data_len = PTR_DIFF(p, data);

	do {
		ret = (cli_send_trans(cli, SMBtrans2, 
				      NULL,           /* Name */
				      -1, 0,          /* fid, flags */
				      &setup, 1, 0,   /* setup, length, max */
				      param, param_len, 10, /* param, length, max */
				      data, data_len, cli->max_xmit /* data, length, max */
				      ) &&
		       cli_receive_trans(cli, SMBtrans2, 
					 &rparam, &rparam_len,
					 &rdata, &rdata_len));
		if (!cli_is_dos_error(cli)) break;
		if (!ret) {
			/* we need to work around a Win95 bug - sometimes
			   it gives ERRSRV/ERRerror temprarily */
			uint8 eclass;
			uint32 ecode;
			cli_dos_error(cli, &eclass, &ecode);
			if (eclass != ERRSRV || ecode != ERRerror) break;
			smb_msleep(100);
		}
	} while (count-- && ret==False);

	if (!ret) {
		return False;
	}

	SAFE_FREE(rdata);
	SAFE_FREE(rparam);
	return True;
}
예제 #8
0
파일: clirap.c 프로젝트: aosm/samba
BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
		   time_t *change_time,
                   time_t *access_time,
                   time_t *write_time, 
		   SMB_OFF_T *size, uint16 *mode)
{
	unsigned int data_len = 0;
	unsigned int param_len = 0;
	unsigned int rparam_len, rdata_len;
	uint16 setup = TRANSACT2_QPATHINFO;
	pstring param;
	char *rparam=NULL, *rdata=NULL;
	int count=8;
	BOOL ret;
	time_t (*date_fn)(struct cli_state *, void *);
	char *p;

	p = param;
	memset(p, 0, 6);
	SSVAL(p, 0, SMB_INFO_STANDARD);
	p += 6;
	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);

	param_len = PTR_DIFF(p, param);

	do {
		ret = (cli_send_trans(cli, SMBtrans2, 
				      NULL,           /* Name */
				      -1, 0,          /* fid, flags */
				      &setup, 1, 0,   /* setup, length, max */
				      param, param_len, 10, /* param, length, max */
				      NULL, data_len, cli->max_xmit /* data, length, max */
				      ) &&
		       cli_receive_trans(cli, SMBtrans2, 
					 &rparam, &rparam_len,
					 &rdata, &rdata_len));
		if (!cli_is_dos_error(cli)) break;
		if (!ret) {
			/* we need to work around a Win95 bug - sometimes
			   it gives ERRSRV/ERRerror temprarily */
			uint8 eclass;
			uint32 ecode;
			cli_dos_error(cli, &eclass, &ecode);
			if (eclass != ERRSRV || ecode != ERRerror) break;
			smb_msleep(100);
		}
	} while (count-- && ret==False);

	if (!ret || !rdata || rdata_len < 22) {
		return False;
	}

	if (cli->win95) {
		date_fn = cli_make_unix_date;
	} else {
		date_fn = cli_make_unix_date2;
	}

	if (change_time) {
		*change_time = date_fn(cli, rdata+0);
	}
	if (access_time) {
		*access_time = date_fn(cli, rdata+4);
	}
	if (write_time) {
		*write_time = date_fn(cli, rdata+8);
	}
	if (size) {
		*size = IVAL(rdata, 12);
	}
	if (mode) {
		*mode = SVAL(rdata,l1_attrFile);
	}

	SAFE_FREE(rdata);
	SAFE_FREE(rparam);
	return True;
}
예제 #9
0
파일: clitrans.c 프로젝트: gojdic/samba
bool cli_receive_nt_trans(struct cli_state *cli,
			  char **param, unsigned int *param_len,
			  char **data, unsigned int *data_len)
{
	unsigned int total_data=0;
	unsigned int total_param=0;
	unsigned int this_data,this_param;
	uint8 eclass;
	uint32 ecode;
	bool ret = False;
	uint16_t mid;

	*data_len = *param_len = 0;

	mid = SVAL(cli->outbuf,smb_mid);

	if (!cli_receive_smb(cli)) {
		cli_state_seqnum_remove(cli, mid);
		return False;
	}

	show_msg(cli->inbuf);

	/* sanity check */
	if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
		DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
			 CVAL(cli->inbuf,smb_com)));
		cli_state_seqnum_remove(cli, mid);
		return(False);
	}

	/*
	 * An NT RPC pipe call can return ERRDOS, ERRmoredata
	 * to a trans call. This is not an error and should not
	 * be treated as such.
	 */
	if (cli_is_dos_error(cli)) {
                cli_dos_error(cli, &eclass, &ecode);
		if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
			goto out;
		}
	}

	/*
	 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
	 */
	if (cli_is_nt_error(cli)) {
		if (!NT_STATUS_EQUAL(cli_nt_error(cli),
				     NT_STATUS_BUFFER_TOO_SMALL)) {
			goto out;
		}
	}

	/* parse out the lengths */
	total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
	total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
	/* Only allow 16 megs. */
	if (total_param > 16*1024*1024) {
		DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
					total_param));
		goto out;
	}
	if (total_data > 16*1024*1024) {
		DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
					total_data));
		goto out;
	}

	/* allocate it */
	if (total_data) {
		/* We know adding 2 is safe as total_data is less
		 * than 16mb (above). */
		*data = (char *)SMB_REALLOC(*data,total_data+2);
		if (!(*data)) {
			DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
			goto out;
		}
	}

	if (total_param) {
		/* We know adding 2 is safe as total_param is less
		 * than 16mb (above). */
		*param = (char *)SMB_REALLOC(*param,total_param+2);
		if (!(*param)) {
			DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
			goto out;
		}
	}

	while (1)  {
		this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
		this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);

		if (this_data + *data_len > total_data ||
		    this_param + *param_len > total_param) {
			DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
			goto out;
		}

		if (this_data + *data_len < this_data ||
				this_data + *data_len < *data_len ||
				this_param + *param_len < this_param ||
				this_param + *param_len < *param_len) {
			DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
			goto out;
		}

		if (this_data) {
			unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
			unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);

			if (data_offset_out > total_data ||
					data_offset_out + this_data > total_data ||
					data_offset_out + this_data < data_offset_out ||
					data_offset_out + this_data < this_data) {
				DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
				goto out;
			}
			if (data_offset_in > cli->bufsize ||
					data_offset_in + this_data >  cli->bufsize ||
					data_offset_in + this_data < data_offset_in ||
					data_offset_in + this_data < this_data) {
				DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
				goto out;
			}

			memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
		}

		if (this_param) {
			unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
			unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);

			if (param_offset_out > total_param ||
					param_offset_out + this_param > total_param ||
					param_offset_out + this_param < param_offset_out ||
					param_offset_out + this_param < this_param) {
				DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
				goto out;
			}
			if (param_offset_in > cli->bufsize ||
					param_offset_in + this_param >  cli->bufsize ||
					param_offset_in + this_param < param_offset_in ||
					param_offset_in + this_param < this_param) {
				DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
				goto out;
			}

			memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
		}

		*data_len += this_data;
		*param_len += this_param;

		if (total_data <= *data_len && total_param <= *param_len) {
			ret = True;
			break;
		}

		if (!cli_receive_smb(cli)) {
			goto out;
		}

		show_msg(cli->inbuf);

		/* sanity check */
		if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
			DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
				 CVAL(cli->inbuf,smb_com)));
			goto out;
		}
		if (cli_is_dos_error(cli)) {
                        cli_dos_error(cli, &eclass, &ecode);
			if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
				goto out;
			}
		}
		/*
		 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
		 */
		if (cli_is_nt_error(cli)) {
			if (!NT_STATUS_EQUAL(cli_nt_error(cli),
					     NT_STATUS_BUFFER_TOO_SMALL)) {
				goto out;
			}
		}

		/* parse out the total lengths again - they can shrink! */
		if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
			total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
		if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
			total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);

		if (total_data <= *data_len && total_param <= *param_len) {
			ret = True;
			break;
		}
	}

  out:

	cli_state_seqnum_remove(cli, mid);

	if (ret) {
		/* Ensure the last 2 bytes of param and data are 2 null
		 * bytes. These are malloc'ed, but not included in any
		 * length counts. This allows cli_XX string reading functions
		 * to safely null terminate. */
		if (total_data) {
			SSVAL(*data,total_data,0);
		}
		if (total_param) {
			SSVAL(*param,total_param,0);
		}
	}

	return ret;
}
예제 #10
0
static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
{
	size_t size = (size_t)cli->max_recv_frag;
	int stream_offset = 0;
	int num_read;
	char *pdata;
	int extra_data_size = ((int)*rdata_offset) + ((int)data_to_read) - (int)prs_data_size(rdata);

	DEBUG(5,("rpc_read: data_to_read: %u rdata offset: %u extra_data_size: %d\n",
		(int)data_to_read, (unsigned int)*rdata_offset, extra_data_size));

	/*
	 * Grow the buffer if needed to accommodate the data to be read.
	 */

	if (extra_data_size > 0) {
		if(!prs_force_grow(rdata, (uint32)extra_data_size)) {
			DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", extra_data_size ));
			return False;
		}
		DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", extra_data_size, prs_data_size(rdata) ));
	}

	pdata = prs_data_p(rdata) + *rdata_offset;

	do /* read data using SMBreadX */
	{
		uint32 ecode;
		uint8 eclass;

		if (size > (size_t)data_to_read)
			size = (size_t)data_to_read;

		num_read = (int)cli_read(cli, cli->nt_pipe_fnum, pdata, (off_t)stream_offset, size);

		DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
		          num_read, stream_offset, data_to_read));

		if (cli_is_dos_error(cli)) {
                        cli_dos_error(cli, &eclass, &ecode);
                        if (eclass != ERRDOS && ecode != ERRmoredata) {
                                DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
                                         eclass, (unsigned int)ecode));
                                return False;
                        }
		}

		data_to_read -= num_read;
		stream_offset += num_read;
		pdata += num_read;

	} while (num_read > 0 && data_to_read > 0);
	/* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */

	/*
	 * Update the current offset into rdata by the amount read.
	 */
	*rdata_offset += stream_offset;

	return True;
}
예제 #11
0
static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata,
			 uint8 expected_pkt_type)
{
	uint32 len;
	char *rparam = NULL;
	uint32 rparam_len = 0;
	uint16 setup[2];
	BOOL first = True;
	BOOL last  = True;
	RPC_HDR rhdr;
	char *pdata = data ? prs_data_p(data) : NULL;
	uint32 data_len = data ? prs_offset(data) : 0;
	char *prdata = NULL;
	uint32 rdata_len = 0;
	uint32 current_offset = 0;
	uint32 fragment_start = 0;
	uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024;
	int auth_padding_len = 0;

	/* Create setup parameters - must be in native byte order. */

	setup[0] = TRANSACT_DCERPCCMD; 
	setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */

	DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum));

	/* Send the RPC request and receive a response.  For short RPC
	   calls (about 1024 bytes or so) the RPC request and response
	   appears in a SMBtrans request and response.  Larger RPC
	   responses are received further on. */

	if (!cli_api_pipe(cli, "\\PIPE\\",
	          setup, 2, 0,                     /* Setup, length, max */
	          NULL, 0, 0,                      /* Params, length, max */
	          pdata, data_len, max_data,   	   /* data, length, max */
	          &rparam, &rparam_len,            /* return params, len */
	          &prdata, &rdata_len))            /* return data, len */
	{
		DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
		return False;
	}

	/* Throw away returned params - we know we won't use them. */

	SAFE_FREE(rparam);

	if (prdata == NULL) {
		DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
			(int)cli->nt_pipe_fnum));
		return False;
	}

	/*
	 * Give this memory as dynamically allocated to the return parse
	 * struct.  
	 */

	prs_give_memory(rdata, prdata, rdata_len, True);
	current_offset = rdata_len;

	/* This next call sets the endian bit correctly in rdata. */

	if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) {
		prs_mem_free(rdata);
		return False;
	}

	if (rhdr.pkt_type == RPC_BINDACK) {
		if (!last && !first) {
			DEBUG(5,("rpc_api_pipe: bug in server (AS/U?), setting fragment first/last ON.\n"));
			first = True;
			last = True;
		}
	}

	if (rhdr.pkt_type == RPC_BINDNACK) {
		DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum));
		prs_mem_free(rdata);
		return False;
	}

	if (rhdr.pkt_type == RPC_RESPONSE) {
		RPC_HDR_RESP rhdr_resp;
		if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) {
			DEBUG(5,("rpc_api_pipe: failed to unmarshal RPC_HDR_RESP.\n"));
			prs_mem_free(rdata);
			return False;
		}
	}

	if (rhdr.pkt_type != expected_pkt_type) {
		DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum, rhdr.pkt_type, expected_pkt_type));
		prs_mem_free(rdata);
		return False;
	}

	DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
	          (unsigned int)len, (unsigned int)rdata_len ));

	/* check if data to be sent back was too large for one SMBtrans */
	/* err status is only informational: the _real_ check is on the
           length */

	if (len > 0) { 
		/* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */

		/* Read the remaining part of the first response fragment */

		if (!rpc_read(cli, rdata, len, &current_offset)) {
			prs_mem_free(rdata);
			return False;
		}
	}

	/*
	 * Now we have a complete PDU, check the auth struct if any was sent.
	 */

	if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
			  rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
		prs_mem_free(rdata);
		return False;
	}

	if (rhdr.auth_len != 0) {
		/*
		 * Drop the auth footers from the current offset.
		 * We need this if there are more fragments.
		 * The auth footers consist of the auth_data and the
		 * preceeding 8 byte auth_header.
		 */
		current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len);
	}
	
	/* 
	 * Only one rpc fragment, and it has been read.
	 */

	if (first && last) {
		DEBUG(6,("rpc_api_pipe: fragment first and last both set\n"));
		return True;
	}

	/*
	 * Read more fragments using SMBreadX until we get one with the
	 * last bit set.
	 */

	while (!last) {
		RPC_HDR_RESP rhdr_resp;
		int num_read;
		char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN];
		prs_struct hps;
		uint8 eclass;
		uint32 ecode;
		
		/*
		 * First read the header of the next PDU.
		 */

		prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
		prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);

		num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
		if (cli_is_dos_error(cli)) {
                        cli_dos_error(cli, &eclass, &ecode);
                        if (eclass != ERRDOS && ecode != ERRmoredata) {
                                DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
                                return False;
                        }
		}

		DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read));

		if (num_read != RPC_HEADER_LEN+RPC_HDR_RESP_LEN) {
			DEBUG(0,("rpc_api_pipe: Error : requested %d bytes, got %d.\n",
				RPC_HEADER_LEN+RPC_HDR_RESP_LEN, num_read ));
			return False;
		}

		/* This call sets the endianness in hps. */

		if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len))
			return False;

		/* Ensure the endianness in rdata is set correctly - must be same as hps. */

		if (hps.bigendian_data != rdata->bigendian_data) {
			DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n",
				rdata->bigendian_data ? "big" : "little",
				hps.bigendian_data ? "big" : "little" ));
			return False;
		}

		if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) {
			DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n"));
			return False;
		}

		if (first) {
			DEBUG(0,("rpc_api_pipe: secondary PDU rpc header has 'first' set !\n"));
			return False;
		}

		/*
		 * Now read the rest of the PDU.
		 */

		if (!rpc_read(cli, rdata, len, &current_offset)) {
			prs_mem_free(rdata);
			return False;
		}

		fragment_start = current_offset - len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;

		/*
		 * Verify any authentication footer.
		 */

		
		if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
				  rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
			prs_mem_free(rdata);
			return False;
		}
		
		if (rhdr.auth_len != 0 ) {
			
			/*
			 * Drop the auth footers from the current offset.
			 * The auth footers consist of the auth_data and the
			 * preceeding 8 byte auth_header.
			 * We need this if there are more fragments.
			 */
			current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len);
		}
	}

	return True;
}
예제 #12
0
const char *cli_errstr(struct cli_state *cli)
{
    fstring cli_error_message;
    uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
    uint8 errclass;
    int i;
    char *result;

    if (!cli->initialised) {
        fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
        goto done;
    }

    /* Was it server socket error ? */
    if (cli->fd == -1 && cli->smb_rw_error) {
        switch(cli->smb_rw_error) {
        case SMB_READ_TIMEOUT:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Call timed out: server did not respond after %d milliseconds",
                     cli->timeout);
            break;
        case SMB_READ_EOF:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Call returned zero bytes (EOF)" );
            break;
        case SMB_READ_ERROR:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Read error: %s", strerror(errno) );
            break;
        case SMB_WRITE_ERROR:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Write error: %s", strerror(errno) );
            break;
        case SMB_READ_BAD_SIG:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Server packet had invalid SMB signature!");
            break;
        case SMB_NO_MEMORY:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Out of memory");
            break;
        default:
            slprintf(cli_error_message, sizeof(cli_error_message) - 1,
                     "Unknown error code %d\n", cli->smb_rw_error );
            break;
        }
        goto done;
    }

    /* Case #1: RAP error */
    if (cli->rap_error) {
        for (i = 0; rap_errmap[i].message != NULL; i++) {
            if (rap_errmap[i].err == cli->rap_error) {
                return rap_errmap[i].message;
            }
        }

        slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d",
                 cli->rap_error);

        goto done;
    }

    /* Case #2: 32-bit NT errors */
    if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
        NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));

        return nt_errstr(status);
    }

    cli_dos_error(cli, &errclass, &errnum);

    /* Case #3: SMB error */

    return cli_smb_errstr(cli);

done:
    result = talloc_strdup(talloc_tos(), cli_error_message);
    SMB_ASSERT(result);
    return result;
}