1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "@(#)smb_find.c 1.7 08/07/30 SMI" 27 28 #include <smbsrv/smb_incl.h> 29 30 31 /* 32 * smb_com_find 33 * 34 * Request Format: (same as core Search Protocol - "Find First" form) 35 * 36 * Client Request Description 37 * ================================== ================================= 38 * 39 * BYTE smb_wct; value = 2 40 * WORD smb_count; max number of entries to find 41 * WORD smb_attr; search attribute 42 * WORD smb_bcc; minimum value = 5 43 * BYTE smb_ident1; ASCII (04) 44 * BYTE smb_pathname[]; filename (may contain global characters) 45 * BYTE smb_ident2; Variable Block (05) 46 * WORD smb_keylen; resume key length (zero if "Find First") 47 * BYTE smb_resumekey[*]; "Find Next" key, * = value of smb_keylen 48 * 49 * Response Format: (same as core Search Protocol) 50 * 51 * Server Response Description 52 * ================================== ================================= 53 * BYTE smb_wct; value = 1 54 * WORD smb_count; number of entries found 55 * WORD smb_bcc; minimum value = 3 56 * BYTE smb_ident; Variable Block (05) 57 * WORD smb_datalen; data length 58 * BYTE smb_data[*]; directory entries 59 * 60 * Directory Information Entry (dir_info) Format: (same as core Search Protocol) 61 * 62 * BYTE find_buf_reserved[21]; reserved (resume_key) 63 * BYTE find_buf_attr; attribute 64 * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx) 65 * where 'xxxxx' is in 2 second increments 66 * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd) 67 * DWORD find_buf_size; file size 68 * STRING find_buf_pname[13]; file name -- ASCII (null terminated) 69 * 70 * The resume_key has the following format: 71 * 72 * BYTE sr_res; reserved: 73 * bit 7 - reserved for consumer use 74 * bit 5,6 - reserved for system use 75 * (must be preserved) 76 * bits 0-4 - reserved for server 77 * (must be preserved) 78 * BYTE sr_name[11]; pathname sought. 79 * Format: 1-8 character file name, 80 * left justified 0-3 character extension, 81 * BYTE sr_findid[1]; uniquely identifies find through 82 * find_close 83 * BYTE sr_server[4]; available for server use 84 * (must be non-zero) 85 * BYTE sr_res[4]; reserved for consumer use 86 * 87 * Service: 88 * 89 * The Find protocol finds the directory entry or group of entries matching the 90 * specified file pathname. The filename portion of the pathname may contain 91 * global (wild card) characters. 92 * 93 * The Find protocol is used to match the find OS/2 system call. The protocols 94 * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching) 95 * a directory. These protocols may be used in place of the core "Search" 96 * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases 97 * where the Search protocol will still be used. 98 * 99 * The format of the Find protocol is the same as the core "Search" protocol. 100 * The difference is that the directory is logically Opened with a Find protocol 101 * and logically closed with the Find Close protocol. This allows the Server to 102 * make better use of its resources. Search buffers are thus held (allowing 103 * search resumption via presenting a "resume_key") until a Find Close protocol 104 * is received. The sr_findid field of each resume key is a unique identifier 105 * (within the session) of the search from "Find" through "Find close". Thus if 106 * the consumer does "Find ahead", any find buffers containing resume keys with 107 * the matching find id may be released when the Find Close is requested. 108 * 109 * As is true of a failing open, if a Find request (Find "first" request where 110 * resume_key is null) fails (no entries are found), no find close protocol is 111 * expected. 112 * 113 * If no global characters are present, a "Find Unique" protocol should be used 114 * (only one entry is expected and find close need not be sent). 115 * 116 * The file path name in the request specifies the file to be sought. The 117 * attribute field indicates the attributes that the file must have. If the 118 * attribute is zero then only normal files are returned. If the system file, 119 * hidden or directory attributes are specified then the search is inclusive -- 120 * both the specified type(s) of files and normal files are returned. If the 121 * volume label attribute is specified then the search is exclusive, and only 122 * the volume label entry is returned 123 * 124 * The max-count field specifies the number of directory entries to be returned. 125 * The response will contain zero or more directory entries as determined by the 126 * count-returned field. No more than max-count entries will be returned. Only 127 * entries that match the sought filename/attribute will be returned. 128 * 129 * The resume_key field must be null (length = 0) on the initial ("Find First") 130 * find request. Subsequent find requests intended to continue a search must 131 * contain the resume_key field extracted from the last directory entry of the 132 * previous response. The resume_key field is self-contained, for on calls 133 * containing a resume_key neither the attribute or pathname fields will be 134 * valid in the request. A find request will terminate when either the 135 * requested maximum number of entries that match the named file are found, or 136 * the end of directory is reached without the maximum number of matches being 137 * found. A response containing no entries indicates that no matching entries 138 * were found between the starting point of the search and the end of directory. 139 * 140 * There may be multiple matching entries in response to a single request as 141 * Find supports "wild cards" in the file name (last component of the pathname). 142 * "?" is the wild single characters, "*" or "null" will match any number of 143 * filename characters within a single part of the filename component. The 144 * filename is divided into two parts -- an eight character name and a three 145 * character extension. The name and extension are divided by a ".". 146 * 147 * If a filename part commences with one or more "?"s then exactly that number 148 * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx" 149 * but not "abcx" or "ax". When a filename part has trailing "?"s then it will 150 * match the specified number of characters or less, e.g., "x??" will match 151 * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename 152 * part, then it is handled as for trailing "?"s "*" or "null" match entire 153 * pathname parts, thus "*.abc" or ".abc" will match any file with an extension 154 * of "abc". "*.*", "*" or "null" will match all files in a directory. 155 * 156 * Unprotected servers require the requester to have read permission on the 157 * subtree containing the directory searched (the share specifies read 158 * permission). 159 * 160 * Protected servers require the requester to have permission to search the 161 * specified directory. 162 * 163 * If a Find requests more data than can be placed in a message of the 164 * max-xmit-size for the TID specified, the server will return only the number 165 * of entries which will fit. 166 * 167 * The number of entries returned will be the minimum of: 168 * 1. The number of entries requested. 169 * 2. The number of (complete) entries that will fit in the negotiated SMB 170 * buffer. 171 * 3. The number of entries that match the requested name pattern and 172 * attributes. 173 * 174 * The error ERRnofiles set in smb_err field of the response header or a zero 175 * value in smb_count of the response indicates no matching entry was found. 176 * 177 * The resume search key returned along with each directory entry is a server 178 * defined key which when returned in the Find Next protocol, allows the 179 * directory search to be resumed at the directory entry fol lowing the one 180 * denoted by the resume search key. 181 * 182 * The date is in the following format: 183 * bits: 184 * 1 1 1 1 1 1 185 * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 186 * y y y y y y y m m m m d d d d d 187 * where: 188 * y - bit of year 0-119 (1980-2099) 189 * m - bit of month 1-12 190 * d - bit of day 1-31 191 * 192 * The time is in the following format: 193 * bits: 194 * 1 1 1 1 1 1 195 * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 196 * h h h h h m m m m m m x x x x x 197 * where: 198 * h - bit of hour (0-23) 199 * m - bit of minute (0-59) 200 * x - bit of 2 second increment 201 * 202 * Find may generate the following errors. 203 * ERRDOS/ERRnofiles 204 * ERRDOS/ERRbadpath 205 * ERRDOS/ERRnoaccess 206 * ERRDOS/ERRbadaccess 207 * ERRDOS/ERRbadshare 208 * ERRSRV/ERRerror 209 * ERRSRV/ERRaccess 210 * ERRSRV/ERRinvnid 211 */ 212 smb_sdrc_t 213 smb_pre_find(smb_request_t *sr) 214 { 215 DTRACE_SMB_1(op__Find__start, smb_request_t *, sr); 216 return (SDRC_SUCCESS); 217 } 218 219 void 220 smb_post_find(smb_request_t *sr) 221 { 222 DTRACE_SMB_1(op__Find__done, smb_request_t *, sr); 223 } 224 225 smb_sdrc_t 226 smb_com_find(smb_request_t *sr) 227 { 228 int rc; 229 unsigned short sattr, count, maxcount; 230 char *path; 231 unsigned char resume_char; 232 uint32_t client_key; 233 uint16_t index; 234 uint32_t cookie; 235 struct smb_node *node; 236 unsigned char type; 237 unsigned short key_len; 238 smb_odir_context_t *pc; 239 boolean_t find_first = B_TRUE; 240 241 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 242 return (SDRC_ERROR); 243 244 rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); 245 if ((rc != 0) || (type != 0x05)) 246 return (SDRC_ERROR); 247 248 if (key_len == 0) { /* begin search */ 249 if (smb_rdir_open(sr, path, sattr) != 0) 250 return (SDRC_ERROR); 251 cookie = 0; 252 } else if (key_len == 21) { 253 sr->smb_sid = 0; 254 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 255 &resume_char, &index, &sr->smb_sid, &client_key) != 0) { 256 /* We don't know which rdir to close */ 257 return (SDRC_ERROR); 258 } 259 260 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, 261 sr->smb_sid); 262 if (sr->sid_odir == NULL) { 263 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 264 ERRDOS, ERRbadfid); 265 return (SDRC_ERROR); 266 } 267 268 cookie = sr->sid_odir->d_cookies[index]; 269 if (cookie != 0) 270 find_first = B_FALSE; 271 } else { 272 /* We don't know which rdir to close */ 273 return (SDRC_ERROR); 274 } 275 276 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 277 278 pc = kmem_zalloc(sizeof (smb_odir_context_t), KM_SLEEP); 279 pc->dc_cookie = cookie; 280 index = 0; 281 count = 0; 282 node = NULL; 283 rc = 0; 284 285 if (maxcount > SMB_MAX_SEARCH) 286 maxcount = SMB_MAX_SEARCH; 287 288 while (count < maxcount) { 289 if ((rc = smb_rdir_next(sr, &node, pc)) != 0) 290 break; 291 292 (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", 293 resume_char, 294 pc->dc_name83, pc->dc_name83+9, 295 index, sr->smb_sid, client_key, 296 pc->dc_dattr & 0xff, 297 smb_gmt2local(sr, pc->dc_attr.sa_vattr.va_mtime.tv_sec), 298 (int32_t)smb_node_get_size(node, &pc->dc_attr), 299 (*pc->dc_shortname) ? pc->dc_shortname : 300 pc->dc_name); 301 302 smb_node_release(node); 303 node = NULL; 304 sr->sid_odir->d_cookies[index] = pc->dc_cookie; 305 count++; 306 index++; 307 } 308 309 kmem_free(pc, sizeof (smb_odir_context_t)); 310 311 if ((rc != 0) && (rc != ENOENT)) { 312 /* returned error by smb_rdir_next() */ 313 smb_rdir_close(sr); 314 smbsr_errno(sr, rc); 315 return (SDRC_ERROR); 316 } 317 318 if (count == 0 && find_first) { 319 smb_rdir_close(sr); 320 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 321 ERRDOS, ERROR_NO_MORE_FILES); 322 return (SDRC_ERROR); 323 } 324 325 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 326 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 327 1, count, rc+3, 5, rc) < 0) { 328 smb_rdir_close(sr); 329 return (SDRC_ERROR); 330 } 331 332 return (SDRC_SUCCESS); 333 } 334 335 /* 336 * smb_com_find_close 337 * 338 * Request Format: (same as core Search Protocol - "Find Next" form) 339 * 340 * Client Request Description 341 * ================================== ================================= 342 * 343 * BYTE smb_wct; value = 2 344 * WORD smb_count; max number of entries to find 345 * WORD smb_attr; search attribute 346 * WORD smb_bcc; minimum value = 5 347 * BYTE smb_ident1; ASCII (04) 348 * BYTE smb_pathname[]; null (may contain only null) 349 * BYTE smb_ident2; Variable Block (05) 350 * WORD smb_keylen; resume (close) key length 351 * (may not be zero) 352 * BYTE smb_resumekey[*]; "Find Close" key 353 * (* = value of smb_keylen) 354 * 355 * Response Format: (same format as core Search Protocol) 356 * 357 * Server Response Description 358 * ================================== ================================= 359 * 360 * BYTE smb_wct; value = 1 361 * WORD smb_reserved; reserved 362 * WORD smb_bcc; value = 3 363 * BYTE smb_ident; Variable Block (05) 364 * WORD smb_datalen; data length (value = 0) 365 * 366 * The resume_key (or close key) has the following format: 367 * 368 * BYTE sr_res; reserved: 369 * bit 7 - reserved for consumer use 370 * bit 5,6 - reserved for system use 371 * (must be preserved) 372 * bits 0-4 - rsvd for server 373 * (must be preserved by consumer) 374 * BYTE sr_name[11]; pathname sought. 375 * Format: 1-8 character file name, 376 * left justified 0-3 character extension, 377 * left justified (in last 3 chars) 378 * BYTE sr_findid[1]; uniquely identifies find 379 * through find_close 380 * BYTE sr_server[4]; available for server use 381 * (must be non-zero) 382 * BYTE sr_res[4]; reserved for consumer use 383 * 384 * Service: 385 * 386 * The Find_Close protocol closes the association between a Find id 387 * returned (in the resume_key) by the Find protocol and the directory 388 * search. 389 * 390 * Whereas the First Find protocol logically opens the directory, 391 * subsequent find protocols presenting a resume_key further "read" the 392 * directory, the Find Close protocol "closes" the directory allowing the 393 * server to free any resources held in support of the directory search. 394 * 395 * The Find Close protocol is used to match the find Close OS/2 396 * system call. The protocols "Find", "Find Unique" and "Find Close" are 397 * methods of reading (or searching) a directory. These protocols may 398 * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has 399 * been negotiated. There may be cases where the Search protocol will still be 400 * used. 401 * 402 * Although only the find id portion the resume key should be 403 * required to identify the search being ter minated, the entire 404 * resume_key as returned in the previous Find, either a "Find First" or "Find 405 * Next" is sent to the server in this protocol. 406 * 407 * Find Close may generate the following errors: 408 * 409 * ERRDOS/ERRbadfid 410 * ERRSRV/ERRerror 411 * ERRSRV/ERRinvnid 412 */ 413 smb_sdrc_t 414 smb_pre_find_close(smb_request_t *sr) 415 { 416 DTRACE_SMB_1(op__FindClose__start, smb_request_t *, sr); 417 return (SDRC_SUCCESS); 418 } 419 420 void 421 smb_post_find_close(smb_request_t *sr) 422 { 423 DTRACE_SMB_1(op__FindClose__done, smb_request_t *, sr); 424 } 425 426 smb_sdrc_t 427 smb_com_find_close(smb_request_t *sr) 428 { 429 unsigned short sattr, maxcount; 430 char *path; 431 unsigned char resume_char; 432 uint32_t resume_key; 433 uint16_t index; 434 unsigned char type; 435 unsigned short key_len; 436 int rc; 437 438 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 439 return (SDRC_ERROR); 440 441 rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); 442 if ((rc != 0) || (type != 0x05)) 443 return (SDRC_ERROR); 444 445 if (key_len == 0) { /* begin search */ 446 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 447 return (SDRC_ERROR); 448 } 449 450 if (key_len == 21) { 451 sr->smb_sid = 0; 452 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 453 &resume_char, &index, &sr->smb_sid, &resume_key) != 0) { 454 return (SDRC_ERROR); 455 } 456 457 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, 458 sr->smb_sid); 459 if (sr->sid_odir == NULL) { 460 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 461 ERRDOS, ERRbadfid); 462 return (SDRC_ERROR); 463 } 464 } else { 465 return (SDRC_ERROR); 466 } 467 468 smb_rdir_close(sr); 469 if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0)) 470 return (SDRC_ERROR); 471 return (SDRC_SUCCESS); 472 } 473