xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_find.c (revision 6030:6bebab7d43d5)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
275331Samw 
285331Samw #include <smbsrv/smb_incl.h>
295331Samw 
305331Samw 
315331Samw /*
325331Samw  * smb_com_find
335331Samw  *
345331Samw  * Request Format: (same as core Search Protocol - "Find First" form)
355331Samw  *
365331Samw  *  Client Request                     Description
375331Samw  *  ================================== =================================
385331Samw  *
395331Samw  *  BYTE  smb_wct;			value = 2
405331Samw  *  WORD  smb_count;			max number of entries to find
415331Samw  *  WORD  smb_attr;			search attribute
425331Samw  *  WORD  smb_bcc;			minimum value = 5
435331Samw  *  BYTE  smb_ident1;			ASCII  (04)
445331Samw  *  BYTE  smb_pathname[];		filename (may contain global characters)
455331Samw  *  BYTE  smb_ident2;			Variable Block (05)
465331Samw  *  WORD  smb_keylen;			resume key length (zero if "Find First")
475331Samw  *  BYTE  smb_resumekey[*];		"Find Next" key, * = value of smb_keylen
485331Samw  *
495331Samw  * Response Format: (same as core Search Protocol)
505331Samw  *
515331Samw  *  Server Response                    Description
525331Samw  *  ================================== =================================
535331Samw  *  BYTE  smb_wct;			value = 1
545331Samw  *  WORD  smb_count;			number of entries found
555331Samw  *  WORD  smb_bcc;			minimum value = 3
565331Samw  *  BYTE  smb_ident;			Variable Block (05)
575331Samw  *  WORD  smb_datalen;			data length
585331Samw  *  BYTE  smb_data[*];			directory entries
595331Samw  *
605331Samw  * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
615331Samw  *
625331Samw  *  BYTE  find_buf_reserved[21];	reserved (resume_key)
635331Samw  *  BYTE  find_buf_attr;		attribute
645331Samw  *  WORD  find_buf_time;		modification time (hhhhh mmmmmm xxxxx)
655331Samw  *					 where 'xxxxx' is in 2 second increments
665331Samw  *  WORD  find_buf_date;		modification date (yyyyyyy mmmm ddddd)
675331Samw  *  DWORD  find_buf_size;		file size
685331Samw  *  STRING find_buf_pname[13];		file name -- ASCII (null terminated)
695331Samw  *
705331Samw  * The resume_key has the following format:
715331Samw  *
725331Samw  *  BYTE  sr_res;			reserved:
735331Samw  *					bit  7 - reserved for consumer use
745331Samw  *					bit  5,6 - reserved for system use
755331Samw  *					   (must be preserved)
765331Samw  *					bits 0-4 - reserved for server
775331Samw  *					   (must be preserved)
785331Samw  *  BYTE  sr_name[11];			pathname sought.
795331Samw  *					 Format: 1-8 character file name,
805331Samw  *					 left justified 0-3 character extension,
815331Samw  *  BYTE  sr_findid[1];			uniquely identifies find through
825331Samw  *					 find_close
835331Samw  *  BYTE  sr_server[4];			available for server use
845331Samw  *					 (must be non-zero)
855331Samw  *  BYTE  sr_res[4];			reserved for consumer use
865331Samw  *
875331Samw  * Service:
885331Samw  *
895331Samw  * The Find protocol finds the directory entry or group of entries matching the
905331Samw  * specified file pathname. The filename portion of the pathname may contain
915331Samw  * global (wild card) characters.
925331Samw  *
935331Samw  * The Find protocol is used to match the find OS/2 system call. The protocols
945331Samw  * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
955331Samw  * a directory. These protocols may be used in place of the core "Search"
965331Samw  * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
975331Samw  * where the Search protocol will still be used.
985331Samw  *
995331Samw  * The format of the Find protocol is the same as the core "Search" protocol.
1005331Samw  * The difference is that the directory is logically Opened with a Find protocol
1015331Samw  * and logically closed with the Find Close protocol. This allows the Server to
1025331Samw  * make better use of its resources. Search buffers are thus held (allowing
1035331Samw  * search resumption via presenting a "resume_key") until a Find Close protocol
1045331Samw  * is received. The sr_findid field of each resume key is a unique identifier
1055331Samw  * (within the session) of the search from "Find" through "Find close". Thus if
1065331Samw  * the consumer does "Find ahead", any find buffers containing resume keys with
1075331Samw  * the matching find id may be released when the Find Close is requested.
1085331Samw  *
1095331Samw  * As is true of a failing open, if a Find request (Find "first" request where
1105331Samw  * resume_key is null) fails (no entries are found), no find close protocol is
1115331Samw  * expected.
1125331Samw  *
1135331Samw  * If no global characters are present, a "Find Unique" protocol should be used
1145331Samw  * (only one entry is expected and find close need not be sent).
1155331Samw  *
1165331Samw  * The file path name in the request specifies the file to be sought. The
1175331Samw  * attribute field indicates the attributes that the file must have. If the
1185331Samw  * attribute is zero then only normal files are returned. If the system file,
1195331Samw  * hidden or directory attributes are specified then the search is inclusive --
1205331Samw  * both the specified type(s) of files and normal files are returned. If the
1215331Samw  * volume label attribute is specified then the search is exclusive, and only
1225331Samw  * the volume label entry is returned
1235331Samw  *
1245331Samw  * The max-count field specifies the number of directory entries to be returned.
1255331Samw  * The response will contain zero or more directory entries as determined by the
1265331Samw  * count-returned field. No more than max-count entries will be returned. Only
1275331Samw  * entries that match the sought filename/attribute will be returned.
1285331Samw  *
1295331Samw  * The resume_key field must be null (length = 0) on the initial ("Find First")
1305331Samw  * find request. Subsequent find requests intended to continue a search must
1315331Samw  * contain the resume_key field extracted from the last directory entry of the
1325331Samw  * previous response. The resume_key field is self-contained, for on calls
1335331Samw  * containing a resume_key neither the attribute or pathname fields will be
1345331Samw  * valid in the request. A find request will terminate when either the
1355331Samw  * requested maximum number of entries that match the named file are found, or
1365331Samw  * the end of directory is reached without the maximum number of matches being
1375331Samw  * found. A response containing no entries indicates that no matching entries
1385331Samw  * were found between the starting point of the search and the end of directory.
1395331Samw  *
1405331Samw  * There may be multiple matching entries in response to a single request as
1415331Samw  * Find supports "wild cards" in the file name (last component of the pathname).
1425331Samw  * "?" is the wild single characters, "*" or "null" will match any number of
1435331Samw  * filename characters within a single part of the filename component. The
1445331Samw  * filename is divided into two parts -- an eight character name and a three
1455331Samw  * character extension. The name and extension are divided by a ".".
1465331Samw  *
1475331Samw  * If a filename part commences with one or more "?"s then exactly that number
1485331Samw  * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx"
1495331Samw  * but not "abcx" or "ax". When a filename part has trailing "?"s then it will
1505331Samw  * match the specified number of characters  or less, e.g., "x??" will match
1515331Samw  * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename
1525331Samw  * part, then it is handled as for trailing "?"s "*" or "null" match entire
1535331Samw  * pathname parts, thus "*.abc" or ".abc" will match any file with an extension
1545331Samw  * of "abc". "*.*", "*" or "null" will match all files in a directory.
1555331Samw  *
1565331Samw  * Unprotected servers require the requester to have read permission on the
1575331Samw  * subtree containing the directory searched (the share specifies read
1585331Samw  * permission).
1595331Samw  *
1605331Samw  * Protected servers require the requester to have permission to search the
1615331Samw  * specified directory.
1625331Samw  *
1635331Samw  * If a Find requests more data than can be placed in a message of the
1645331Samw  * max-xmit-size for the TID specified, the server will return only the number
1655331Samw  * of entries which will fit.
1665331Samw  *
1675331Samw  * The number of entries returned will be the minimum of:
1685331Samw  *    1. The number of entries requested.
1695331Samw  *    2. The number of (complete) entries that will fit in the negotiated SMB
1705331Samw  *       buffer.
1715331Samw  *    3. The number of entries that match the requested name pattern and
1725331Samw  *       attributes.
1735331Samw  *
1745331Samw  * The error ERRnofiles set in smb_err field of the response header or a zero
1755331Samw  * value in smb_count of the response indicates no matching entry was found.
1765331Samw  *
1775331Samw  * The resume search key returned along with each directory entry is a server
1785331Samw  * defined key which when returned in the Find Next protocol, allows the
1795331Samw  * directory search to be resumed at the directory entry fol lowing the one
1805331Samw  * denoted by the resume search key.
1815331Samw  *
1825331Samw  * The date is in the following format:
1835331Samw  *   bits:
1845331Samw  *	1 1 1 1  1 1
1855331Samw  *	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
1865331Samw  *	y y y y  y y y m  m m m d  d d d d
1875331Samw  *   where:
1885331Samw  *	y - bit of year 0-119 (1980-2099)
1895331Samw  *	m - bit of month 1-12
1905331Samw  *	d - bit of day 1-31
1915331Samw  *
1925331Samw  * The time is in the following format:
1935331Samw  *   bits:
1945331Samw  *	1 1 1 1  1 1
1955331Samw  *	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
1965331Samw  *	h h h h  h m m m  m m m x  x x x x
1975331Samw  *   where:
1985331Samw  *	h - bit of hour (0-23)
1995331Samw  *	m - bit of minute (0-59)
2005331Samw  *	x - bit of 2 second increment
2015331Samw  *
2025331Samw  * Find may generate the following errors.
2035331Samw  *	ERRDOS/ERRnofiles
2045331Samw  *	ERRDOS/ERRbadpath
2055331Samw  *	ERRDOS/ERRnoaccess
2065331Samw  *	ERRDOS/ERRbadaccess
2075331Samw  *	ERRDOS/ERRbadshare
2085331Samw  *	ERRSRV/ERRerror
2095331Samw  *	ERRSRV/ERRaccess
2105331Samw  *	ERRSRV/ERRinvnid
2115331Samw  */
212*6030Sjb150015 smb_sdrc_t
2135331Samw smb_com_find(struct smb_request *sr)
2145331Samw {
2155331Samw 	int			rc;
2165331Samw 	unsigned short		sattr, count, maxcount;
2175331Samw 	char			*path;
2185331Samw 	char			filename[14];
2195331Samw 	uint32_t		cookie;
2205331Samw 	struct smb_node		*node;
2215331Samw 	unsigned char		type;
2225331Samw 	unsigned short		key_len;
2235331Samw 	smb_odir_context_t *pc;
2245331Samw 
225*6030Sjb150015 	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
226*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2275331Samw 
228*6030Sjb150015 	rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
229*6030Sjb150015 	if ((rc != 0) || (type != 0x05))
230*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2315331Samw 
2325331Samw 	if (key_len == 0) {		/* begin search */
233*6030Sjb150015 		if (smb_rdir_open(sr, path, sattr) != 0)
234*6030Sjb150015 			return (SDRC_ERROR_REPLY);
2355331Samw 		cookie = 0;
2365331Samw 	} else if (key_len == 21) {
2375331Samw 		sr->smb_sid = 0;
2385331Samw 		if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
2395331Samw 		    filename, &sr->smb_sid, &cookie) != 0) {
2405331Samw 			/* We don't know which rdir to close */
241*6030Sjb150015 			return (SDRC_ERROR_REPLY);
2425331Samw 		}
2435331Samw 
2445331Samw 		sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
2455331Samw 		    sr->smb_sid);
2465331Samw 		if (sr->sid_odir == NULL) {
2475772Sas200622 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
2485331Samw 			    ERRDOS, ERRbadfid);
249*6030Sjb150015 			return (SDRC_ERROR_REPLY);
2505331Samw 		}
2515331Samw 
2525331Samw 		cookie--;			/* +1 when returned */
2535331Samw 	} else {
2545331Samw 		/* We don't know which rdir to close */
255*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2565331Samw 	}
2575331Samw 
2585331Samw 	(void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
2595331Samw 
2605331Samw 	pc = MEM_ZALLOC("smb", sizeof (*pc));
2615331Samw 	pc->dc_cookie = cookie;
2625331Samw 	count = 0;
2635331Samw 	node = (struct smb_node *)0;
2645331Samw 	rc = 0;
2655331Samw 	while (count < maxcount) {
2665331Samw 		if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
2675331Samw 			break;
2685331Samw 
2695331Samw 		(void) smb_encode_mbc(&sr->reply, ".8c3cbl4.bYl13c",
2705331Samw 		    pc->dc_name83, pc->dc_name83+9, sr->smb_sid,
2715331Samw 		    pc->dc_cookie+1, pc->dc_dattr,
2725331Samw 		    smb_gmt_to_local_time(pc->dc_attr.sa_vattr.va_mtime.tv_sec),
2735331Samw 		    (int32_t)smb_node_get_size(node, &pc->dc_attr),
2745331Samw 		    (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
2755331Samw 		smb_node_release(node);
2765331Samw 		node = (struct smb_node *)0;
2775331Samw 		count++;
2785331Samw 	}
2795331Samw 	MEM_FREE("smb", pc);
2805331Samw 
2815331Samw 	if ((rc != 0) && (rc != ENOENT)) {
2825331Samw 		/* returned error by smb_rdir_next() */
2835331Samw 		smb_rdir_close(sr);
2845772Sas200622 		smbsr_errno(sr, rc);
285*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2865331Samw 	}
2875331Samw 
2885331Samw 	if (count == 0) {
2895331Samw 		smb_rdir_close(sr);
2905772Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRnofiles);
291*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2925331Samw 	}
2935331Samw 
2945331Samw 	rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
295*6030Sjb150015 	if (smb_poke_mbc(&sr->reply, sr->cur_reply_offset, "bwwbw",
296*6030Sjb150015 	    1, count, rc+3, 5, rc) < 0) {
2975331Samw 		smb_rdir_close(sr);
298*6030Sjb150015 		return (SDRC_ERROR_REPLY);
2995331Samw 	}
3005331Samw 
3015331Samw 	return (SDRC_NORMAL_REPLY);
3025331Samw }
3035331Samw 
3045331Samw /*
3055331Samw  * smb_com_find_close
3065331Samw  *
3075331Samw  * Request Format: (same as core Search Protocol - "Find Next" form)
3085331Samw  *
3095331Samw  *  Client Request                     Description
3105331Samw  *  ================================== =================================
3115331Samw  *
3125331Samw  *  BYTE  smb_wct;			value = 2
3135331Samw  *  WORD  smb_count;			max number of entries to find
3145331Samw  *  WORD  smb_attr;			search attribute
3155331Samw  *  WORD  smb_bcc;			minimum value = 5
3165331Samw  *  BYTE  smb_ident1;			ASCII  (04)
3175331Samw  *  BYTE  smb_pathname[];		null (may contain only null)
3185331Samw  *  BYTE  smb_ident2;			Variable Block (05)
3195331Samw  *  WORD  smb_keylen;			resume (close) key length
3205331Samw  *					 (may not be zero)
3215331Samw  *  BYTE  smb_resumekey[*];		"Find Close" key
3225331Samw  *					 (* = value of smb_keylen)
3235331Samw  *
3245331Samw  * Response Format: (same format as core Search Protocol)
3255331Samw  *
3265331Samw  *  Server Response                    Description
3275331Samw  *  ================================== =================================
3285331Samw  *
3295331Samw  *  BYTE  smb_wct;			value = 1
3305331Samw  *  WORD  smb_reserved;			reserved
3315331Samw  *  WORD  smb_bcc;			value = 3
3325331Samw  *  BYTE  smb_ident;			Variable Block (05)
3335331Samw  *  WORD  smb_datalen;			data length (value = 0)
3345331Samw  *
3355331Samw  *  The resume_key (or close key) has the following format:
3365331Samw  *
3375331Samw  *  BYTE  sr_res;			reserved:
3385331Samw  * 					bit  7 - reserved for consumer use
3395331Samw  *					bit  5,6 - reserved for system use
3405331Samw  *					  (must be preserved)
3415331Samw  *					bits 0-4 - rsvd for server
3425331Samw  *					  (must be preserved by consumer)
3435331Samw  *  BYTE  sr_name[11];			pathname sought.
3445331Samw  * 					Format: 1-8 character file name,
3455331Samw  *					left justified 0-3 character extension,
3465331Samw  *					left justified (in last 3 chars)
3475331Samw  *  BYTE  sr_findid[1];			uniquely identifies find
3485331Samw  * 					through find_close
3495331Samw  *  BYTE  sr_server[4];			available for server use
3505331Samw  * 					(must be non-zero)
3515331Samw  *  BYTE  sr_res[4];			reserved for consumer use
3525331Samw  *
3535331Samw  *  Service:
3545331Samw  *
3555331Samw  * The  Find_Close  protocol  closes  the  association  between  a  Find  id
3565331Samw  * returned  (in  the  resume_key)  by  the Find protocol and the directory
3575331Samw  * search.
3585331Samw  *
3595331Samw  * Whereas  the  First  Find  protocol  logically  opens  the  directory,
3605331Samw  * subsequent  find  protocols  presenting  a resume_key  further "read" the
3615331Samw  * directory,  the  Find  Close  protocol "closes" the  directory  allowing  the
3625331Samw  * server to free any resources held in support of the directory search.
3635331Samw  *
3645331Samw  * The  Find  Close  protocol  is  used  to  match  the  find  Close  OS/2
3655331Samw  * system call.  The  protocols "Find", "Find Unique" and "Find  Close" are
3665331Samw  * methods  of reading  (or  searching)  a  directory.  These  protocols  may
3675331Samw  * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has
3685331Samw  * been negotiated.  There may be cases where the Search protocol will still be
3695331Samw  * used.
3705331Samw  *
3715331Samw  * Although  only  the  find  id  portion  the  resume  key  should  be
3725331Samw  * required to  identify  the  search  being  ter minated,  the entire
3735331Samw  * resume_key as returned in  the previous Find, either a "Find  First" or "Find
3745331Samw  * Next" is sent to the server in this protocol.
3755331Samw  *
3765331Samw  * Find Close may generate the following errors:
3775331Samw  *
3785331Samw  *	ERRDOS/ERRbadfid
3795331Samw  *	ERRSRV/ERRerror
3805331Samw  *	ERRSRV/ERRinvnid
3815331Samw  */
382*6030Sjb150015 smb_sdrc_t
3835331Samw smb_com_find_close(struct smb_request *sr)
3845331Samw {
3855331Samw 	unsigned short		sattr, maxcount;
3865331Samw 	char			*path;
3875331Samw 	char			filename[14];
3885331Samw 	uint32_t		cookie;
3895331Samw 	unsigned char		type;
3905331Samw 	unsigned short		key_len;
3915331Samw 	int			rc;
3925331Samw 
393*6030Sjb150015 	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
394*6030Sjb150015 		return (SDRC_ERROR_REPLY);
3955331Samw 
3965331Samw 	rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
397*6030Sjb150015 	if ((rc != 0) || (type != 0x05))
398*6030Sjb150015 		return (SDRC_ERROR_REPLY);
3995331Samw 
4005331Samw 	if (key_len == 0) {		/* begin search */
4015772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
402*6030Sjb150015 		return (SDRC_ERROR_REPLY);
4035331Samw 	}
4045331Samw 
4055331Samw 	if (key_len == 21) {
4065331Samw 		sr->smb_sid = 0;
4075331Samw 		if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
4085331Samw 		    filename, &sr->smb_sid, &cookie) != 0) {
409*6030Sjb150015 			return (SDRC_ERROR_REPLY);
4105331Samw 		}
4115331Samw 
4125331Samw 		sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
4135331Samw 		    sr->smb_sid);
4145331Samw 		if (sr->sid_odir == NULL) {
4155772Sas200622 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
4165331Samw 			    ERRDOS, ERRbadfid);
417*6030Sjb150015 			return (SDRC_ERROR_REPLY);
4185331Samw 		}
4195331Samw 
4205331Samw 		cookie--;		/* +1 when returned */
4215331Samw 	} else {
422*6030Sjb150015 		return (SDRC_ERROR_REPLY);
4235331Samw 	}
4245331Samw 
4255331Samw 	smb_rdir_close(sr);
426*6030Sjb150015 	if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0))
427*6030Sjb150015 		return (SDRC_ERROR_REPLY);
4285331Samw 	return (SDRC_NORMAL_REPLY);
4295331Samw }
430