00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "includes.h"
00022
00023
00024
00025
00026
00027 extern struct current_user current_user;
00028
00029
00030 #define END_OF_DIRECTORY_OFFSET ((long)-1)
00031 #define START_OF_DIRECTORY_OFFSET ((long)0)
00032 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
00033
00034
00035
00036 struct name_cache_entry {
00037 char *name;
00038 long offset;
00039 };
00040
00041 struct smb_Dir {
00042 connection_struct *conn;
00043 SMB_STRUCT_DIR *dir;
00044 long offset;
00045 char *dir_path;
00046 size_t name_cache_size;
00047 struct name_cache_entry *name_cache;
00048 unsigned int name_cache_index;
00049 unsigned int file_number;
00050 };
00051
00052 struct dptr_struct {
00053 struct dptr_struct *next, *prev;
00054 int dnum;
00055 uint16 spid;
00056 struct connection_struct *conn;
00057 struct smb_Dir *dir_hnd;
00058 BOOL expect_close;
00059 char *wcard;
00060 uint32 attr;
00061 char *path;
00062 BOOL has_wild;
00063 BOOL did_stat;
00064 };
00065
00066 static struct bitmap *dptr_bmap;
00067 static struct dptr_struct *dirptrs;
00068 static int dirhandles_open = 0;
00069
00070 #define INVALID_DPTR_KEY (-3)
00071
00072
00073
00074
00075
00076 void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
00077 {
00078 char *p;
00079 pstring mask2;
00080
00081 pstrcpy(mask2,mask);
00082
00083 if ((mode & aDIR) != 0)
00084 size = 0;
00085
00086 memset(buf+1,' ',11);
00087 if ((p = strchr_m(mask2,'.')) != NULL) {
00088 *p = 0;
00089 push_ascii(buf+1,mask2,8, 0);
00090 push_ascii(buf+9,p+1,3, 0);
00091 *p = '.';
00092 } else
00093 push_ascii(buf+1,mask2,11, 0);
00094
00095 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
00096 SCVAL(buf,21,mode);
00097 srv_put_dos_date(buf,22,date);
00098 SSVAL(buf,26,size & 0xFFFF);
00099 SSVAL(buf,28,(size >> 16)&0xFFFF);
00100
00101
00102 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
00103 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
00104 }
00105
00106
00107
00108
00109
00110 void init_dptrs(void)
00111 {
00112 static BOOL dptrs_init=False;
00113
00114 if (dptrs_init)
00115 return;
00116
00117 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
00118
00119 if (!dptr_bmap)
00120 exit_server("out of memory in init_dptrs");
00121
00122 dptrs_init = True;
00123 }
00124
00125
00126
00127
00128
00129 static void dptr_idle(struct dptr_struct *dptr)
00130 {
00131 if (dptr->dir_hnd) {
00132 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
00133 CloseDir(dptr->dir_hnd);
00134 dptr->dir_hnd = NULL;
00135 }
00136 }
00137
00138
00139
00140
00141
00142 static void dptr_idleoldest(void)
00143 {
00144 struct dptr_struct *dptr;
00145
00146
00147
00148
00149 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
00150 ;
00151
00152 if(!dptr) {
00153 DEBUG(0,("No dptrs available to idle ?\n"));
00154 return;
00155 }
00156
00157
00158
00159
00160
00161 for(; dptr; dptr = dptr->prev) {
00162 if (dptr->dir_hnd) {
00163 dptr_idle(dptr);
00164 return;
00165 }
00166 }
00167 }
00168
00169
00170
00171
00172
00173 static struct dptr_struct *dptr_get(int key, BOOL forclose)
00174 {
00175 struct dptr_struct *dptr;
00176
00177 for(dptr = dirptrs; dptr; dptr = dptr->next) {
00178 if(dptr->dnum == key) {
00179 if (!forclose && !dptr->dir_hnd) {
00180 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
00181 dptr_idleoldest();
00182 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
00183 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
00184 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
00185 strerror(errno)));
00186 return False;
00187 }
00188 }
00189 DLIST_PROMOTE(dirptrs,dptr);
00190 return dptr;
00191 }
00192 }
00193 return(NULL);
00194 }
00195
00196
00197
00198
00199
00200 char *dptr_path(int key)
00201 {
00202 struct dptr_struct *dptr = dptr_get(key, False);
00203 if (dptr)
00204 return(dptr->path);
00205 return(NULL);
00206 }
00207
00208
00209
00210
00211
00212 char *dptr_wcard(int key)
00213 {
00214 struct dptr_struct *dptr = dptr_get(key, False);
00215 if (dptr)
00216 return(dptr->wcard);
00217 return(NULL);
00218 }
00219
00220
00221
00222
00223
00224 uint16 dptr_attr(int key)
00225 {
00226 struct dptr_struct *dptr = dptr_get(key, False);
00227 if (dptr)
00228 return(dptr->attr);
00229 return(0);
00230 }
00231
00232
00233
00234
00235
00236 static void dptr_close_internal(struct dptr_struct *dptr)
00237 {
00238 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
00239
00240 DLIST_REMOVE(dirptrs, dptr);
00241
00242
00243
00244
00245
00246
00247 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
00248 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
00249 dptr->dnum ));
00250 }
00251
00252 bitmap_clear(dptr_bmap, dptr->dnum - 1);
00253
00254 if (dptr->dir_hnd) {
00255 CloseDir(dptr->dir_hnd);
00256 }
00257
00258
00259 SAFE_FREE(dptr->wcard);
00260 string_set(&dptr->path,"");
00261 SAFE_FREE(dptr);
00262 }
00263
00264
00265
00266
00267
00268 void dptr_close(int *key)
00269 {
00270 struct dptr_struct *dptr;
00271
00272 if(*key == INVALID_DPTR_KEY)
00273 return;
00274
00275
00276 if (*key == -1) {
00277 struct dptr_struct *next;
00278 for(dptr = dirptrs; dptr; dptr = next) {
00279 next = dptr->next;
00280 dptr_close_internal(dptr);
00281 }
00282 *key = INVALID_DPTR_KEY;
00283 return;
00284 }
00285
00286 dptr = dptr_get(*key, True);
00287
00288 if (!dptr) {
00289 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
00290 return;
00291 }
00292
00293 dptr_close_internal(dptr);
00294
00295 *key = INVALID_DPTR_KEY;
00296 }
00297
00298
00299
00300
00301
00302 void dptr_closecnum(connection_struct *conn)
00303 {
00304 struct dptr_struct *dptr, *next;
00305 for(dptr = dirptrs; dptr; dptr = next) {
00306 next = dptr->next;
00307 if (dptr->conn == conn)
00308 dptr_close_internal(dptr);
00309 }
00310 }
00311
00312
00313
00314
00315
00316 void dptr_idlecnum(connection_struct *conn)
00317 {
00318 struct dptr_struct *dptr;
00319 for(dptr = dirptrs; dptr; dptr = dptr->next) {
00320 if (dptr->conn == conn && dptr->dir_hnd)
00321 dptr_idle(dptr);
00322 }
00323 }
00324
00325
00326
00327
00328
00329 void dptr_closepath(char *path,uint16 spid)
00330 {
00331 struct dptr_struct *dptr, *next;
00332 for(dptr = dirptrs; dptr; dptr = next) {
00333 next = dptr->next;
00334 if (spid == dptr->spid && strequal(dptr->path,path))
00335 dptr_close_internal(dptr);
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345 static void dptr_close_oldest(BOOL old)
00346 {
00347 struct dptr_struct *dptr;
00348
00349
00350
00351
00352 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
00353 ;
00354
00355 if(!dptr) {
00356 DEBUG(0,("No old dptrs available to close oldest ?\n"));
00357 return;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366 for(; dptr; dptr = dptr->prev) {
00367 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
00368 (!old && (dptr->dnum > 255))) {
00369 dptr_close_internal(dptr);
00370 return;
00371 }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
00385 const char *wcard, BOOL wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
00386 {
00387 struct dptr_struct *dptr = NULL;
00388 struct smb_Dir *dir_hnd;
00389 const char *dir2;
00390 NTSTATUS status;
00391
00392 DEBUG(5,("dptr_create dir=%s\n", path));
00393
00394 if (!wcard) {
00395 return NT_STATUS_INVALID_PARAMETER;
00396 }
00397
00398 status = check_name(conn,path);
00399 if (!NT_STATUS_IS_OK(status)) {
00400 return status;
00401 }
00402
00403
00404 dir2 = path;
00405 if (!*dir2)
00406 dir2 = ".";
00407
00408 dir_hnd = OpenDir(conn, dir2, wcard, attr);
00409 if (!dir_hnd) {
00410 return map_nt_error_from_unix(errno);
00411 }
00412
00413 string_set(&conn->dirpath,dir2);
00414
00415 if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
00416 dptr_idleoldest();
00417 }
00418
00419 dptr = SMB_MALLOC_P(struct dptr_struct);
00420 if(!dptr) {
00421 DEBUG(0,("malloc fail in dptr_create.\n"));
00422 CloseDir(dir_hnd);
00423 return NT_STATUS_NO_MEMORY;
00424 }
00425
00426 ZERO_STRUCTP(dptr);
00427
00428 if(old_handle) {
00429
00430
00431
00432
00433
00434
00435 dptr->dnum = bitmap_find(dptr_bmap, 0);
00436
00437 if(dptr->dnum == -1 || dptr->dnum > 254) {
00438
00439
00440
00441
00442
00443
00444
00445 dptr_close_oldest(True);
00446
00447
00448 dptr->dnum = bitmap_find(dptr_bmap, 0);
00449 if(dptr->dnum == -1 || dptr->dnum > 254) {
00450 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
00451 SAFE_FREE(dptr);
00452 CloseDir(dir_hnd);
00453 return NT_STATUS_TOO_MANY_OPENED_FILES;
00454 }
00455 }
00456 } else {
00457
00458
00459
00460
00461
00462
00463 dptr->dnum = bitmap_find(dptr_bmap, 255);
00464
00465 if(dptr->dnum == -1 || dptr->dnum < 255) {
00466
00467
00468
00469
00470
00471
00472
00473
00474 dptr_close_oldest(False);
00475
00476
00477 dptr->dnum = bitmap_find(dptr_bmap, 255);
00478
00479 if(dptr->dnum == -1 || dptr->dnum < 255) {
00480 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
00481 SAFE_FREE(dptr);
00482 CloseDir(dir_hnd);
00483 return NT_STATUS_TOO_MANY_OPENED_FILES;
00484 }
00485 }
00486 }
00487
00488 bitmap_set(dptr_bmap, dptr->dnum);
00489
00490 dptr->dnum += 1;
00491
00492 string_set(&dptr->path,dir2);
00493 dptr->conn = conn;
00494 dptr->dir_hnd = dir_hnd;
00495 dptr->spid = spid;
00496 dptr->expect_close = expect_close;
00497 dptr->wcard = SMB_STRDUP(wcard);
00498 if (!dptr->wcard) {
00499 bitmap_clear(dptr_bmap, dptr->dnum - 1);
00500 SAFE_FREE(dptr);
00501 CloseDir(dir_hnd);
00502 return NT_STATUS_NO_MEMORY;
00503 }
00504 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
00505 dptr->has_wild = True;
00506 } else {
00507 dptr->has_wild = wcard_has_wild;
00508 }
00509
00510 dptr->attr = attr;
00511
00512 DLIST_ADD(dirptrs, dptr);
00513
00514 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
00515 dptr->dnum,path,expect_close));
00516
00517 *dptr_ret = dptr;
00518
00519 return NT_STATUS_OK;
00520 }
00521
00522
00523
00524
00525
00526
00527 int dptr_CloseDir(struct dptr_struct *dptr)
00528 {
00529 DLIST_REMOVE(dirptrs, dptr);
00530 return CloseDir(dptr->dir_hnd);
00531 }
00532
00533 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
00534 {
00535 SeekDir(dptr->dir_hnd, offset);
00536 }
00537
00538 long dptr_TellDir(struct dptr_struct *dptr)
00539 {
00540 return TellDir(dptr->dir_hnd);
00541 }
00542
00543 BOOL dptr_has_wild(struct dptr_struct *dptr)
00544 {
00545 return dptr->has_wild;
00546 }
00547
00548 int dptr_dnum(struct dptr_struct *dptr)
00549 {
00550 return dptr->dnum;
00551 }
00552
00553
00554
00555
00556
00557 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
00558 {
00559
00560 const char *name;
00561 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
00562 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
00563 return name;
00564 }
00565 }
00566 return NULL;
00567 }
00568
00569
00570
00571
00572
00573 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
00574 {
00575 SET_STAT_INVALID(*pst);
00576
00577 if (dptr->has_wild) {
00578 return dptr_normal_ReadDirName(dptr, poffset, pst);
00579 }
00580
00581
00582
00583 if (*poffset == END_OF_DIRECTORY_OFFSET) {
00584 return NULL;
00585 }
00586
00587 if (!dptr->did_stat) {
00588 pstring pathreal;
00589
00590
00591
00592
00593
00594 dptr->did_stat = True;
00595
00596
00597 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
00598
00599
00600
00601 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
00602 return NULL;
00603 }
00604
00605 if (VALID_STAT(*pst)) {
00606
00607
00608 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
00609 return dptr->wcard;
00610 }
00611
00612 pstrcpy(pathreal,dptr->path);
00613 pstrcat(pathreal,"/");
00614 pstrcat(pathreal,dptr->wcard);
00615
00616 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
00617
00618
00619 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
00620 return dptr->wcard;
00621 } else {
00622
00623
00624 if (errno != ENOENT && errno != ENOTDIR) {
00625
00626
00627 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
00628 return dptr->wcard;
00629 }
00630 }
00631
00632
00633
00634
00635 if (dptr->conn->case_sensitive) {
00636
00637
00638 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
00639 return NULL;
00640 }
00641 }
00642 return dptr_normal_ReadDirName(dptr, poffset, pst);
00643 }
00644
00645
00646
00647
00648
00649 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
00650 {
00651 SET_STAT_INVALID(*pst);
00652
00653 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
00654
00655 *poffset = END_OF_DIRECTORY_OFFSET;
00656 return False;
00657 }
00658
00659 return SearchDir(dptr->dir_hnd, name, poffset);
00660 }
00661
00662
00663
00664
00665
00666 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
00667 {
00668 DirCacheAdd(dptr->dir_hnd, name, offset);
00669 }
00670
00671
00672
00673
00674
00675 BOOL dptr_fill(char *buf1,unsigned int key)
00676 {
00677 unsigned char *buf = (unsigned char *)buf1;
00678 struct dptr_struct *dptr = dptr_get(key, False);
00679 uint32 offset;
00680 if (!dptr) {
00681 DEBUG(1,("filling null dirptr %d\n",key));
00682 return(False);
00683 }
00684 offset = (uint32)TellDir(dptr->dir_hnd);
00685 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
00686 (long)dptr->dir_hnd,(int)offset));
00687 buf[0] = key;
00688 SIVAL(buf,1,offset);
00689 return(True);
00690 }
00691
00692
00693
00694
00695
00696 struct dptr_struct *dptr_fetch(char *buf,int *num)
00697 {
00698 unsigned int key = *(unsigned char *)buf;
00699 struct dptr_struct *dptr = dptr_get(key, False);
00700 uint32 offset;
00701 long seekoff;
00702
00703 if (!dptr) {
00704 DEBUG(3,("fetched null dirptr %d\n",key));
00705 return(NULL);
00706 }
00707 *num = key;
00708 offset = IVAL(buf,1);
00709 if (offset == (uint32)-1) {
00710 seekoff = END_OF_DIRECTORY_OFFSET;
00711 } else {
00712 seekoff = (long)offset;
00713 }
00714 SeekDir(dptr->dir_hnd,seekoff);
00715 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
00716 key,dptr_path(key),(int)seekoff));
00717 return(dptr);
00718 }
00719
00720
00721
00722
00723
00724 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
00725 {
00726 struct dptr_struct *dptr = dptr_get(dptr_num, False);
00727
00728 if (!dptr) {
00729 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
00730 return(NULL);
00731 }
00732 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
00733 return(dptr);
00734 }
00735
00736
00737
00738
00739
00740 BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
00741 {
00742 uint32 mask;
00743
00744
00745 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
00746 return False;
00747
00748
00749
00750
00751 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM));
00752 if(mask) {
00753 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)
00754 return True;
00755 else
00756 return False;
00757 }
00758
00759 return True;
00760 }
00761
00762 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
00763 {
00764 mangle_map(filename,True,False,conn->params);
00765 return mask_match_search(filename,mask,False);
00766 }
00767
00768
00769
00770
00771
00772 BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
00773 SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
00774 {
00775 const char *dname;
00776 BOOL found = False;
00777 SMB_STRUCT_STAT sbuf;
00778 pstring path;
00779 pstring pathreal;
00780 pstring filename;
00781 BOOL needslash;
00782
00783 *path = *pathreal = *filename = 0;
00784
00785 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
00786
00787 if (!conn->dirptr)
00788 return(False);
00789
00790 while (!found) {
00791 long curoff = dptr_TellDir(conn->dirptr);
00792 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
00793
00794 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
00795 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
00796
00797 if (dname == NULL)
00798 return(False);
00799
00800 pstrcpy(filename,dname);
00801
00802
00803
00804
00805
00806 if ((strcmp(mask,"*.*") == 0) ||
00807 mask_match_search(filename,mask,False) ||
00808 mangle_mask_match(conn,filename,mask)) {
00809
00810 if (!mangle_is_8_3(filename, False, conn->params))
00811 mangle_map(filename,True,False,
00812 conn->params);
00813
00814 pstrcpy(fname,filename);
00815 *path = 0;
00816 pstrcpy(path,conn->dirpath);
00817 if(needslash)
00818 pstrcat(path,"/");
00819 pstrcpy(pathreal,path);
00820 pstrcat(path,fname);
00821 pstrcat(pathreal,dname);
00822 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
00823 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
00824 continue;
00825 }
00826
00827 *mode = dos_mode(conn,pathreal,&sbuf);
00828
00829 if (!dir_check_ftype(conn,*mode,dirtype)) {
00830 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype));
00831 continue;
00832 }
00833
00834 *size = sbuf.st_size;
00835 *date = sbuf.st_mtime;
00836
00837 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
00838
00839 found = True;
00840
00841 DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff);
00842 }
00843 }
00844
00845 return(found);
00846 }
00847
00848
00849
00850
00851
00852
00853
00854 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
00855 {
00856 SEC_DESC *psd = NULL;
00857 size_t sd_size;
00858 files_struct *fsp;
00859 NTSTATUS status;
00860 uint32 access_granted;
00861
00862
00863
00864
00865
00866
00867 if (conn->admin_user) {
00868 return True;
00869 }
00870
00871
00872 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
00873 DEBUG(10,("user_can_read_file: SMB_VFS_STAT failed for file %s with error %s\n",
00874 name, strerror(errno) ));
00875 return False;
00876 }
00877
00878
00879
00880 if(S_ISDIR(pst->st_mode)) {
00881 status = open_directory(conn, name, pst,
00882 READ_CONTROL_ACCESS,
00883 FILE_SHARE_READ|FILE_SHARE_WRITE,
00884 FILE_OPEN,
00885 0,
00886 FILE_ATTRIBUTE_DIRECTORY,
00887 NULL, &fsp);
00888 } else {
00889 status = open_file_stat(conn, name, pst, &fsp);
00890 }
00891
00892 if (!NT_STATUS_IS_OK(status)) {
00893 return False;
00894 }
00895
00896
00897 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
00898 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
00899 close_file(fsp, NORMAL_CLOSE);
00900
00901
00902 if (!sd_size) {
00903 return False;
00904 }
00905
00906 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
00907 &access_granted, &status);
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
00918 {
00919 SEC_DESC *psd = NULL;
00920 size_t sd_size;
00921 files_struct *fsp;
00922 int info;
00923 NTSTATUS status;
00924 uint32 access_granted;
00925
00926
00927
00928
00929
00930
00931 if (conn->admin_user) {
00932 return True;
00933 }
00934
00935
00936 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
00937 return False;
00938 }
00939
00940
00941
00942 if(S_ISDIR(pst->st_mode)) {
00943 return True;
00944 } else {
00945 status = open_file_ntcreate(conn, name, pst,
00946 FILE_WRITE_ATTRIBUTES,
00947 FILE_SHARE_READ|FILE_SHARE_WRITE,
00948 FILE_OPEN,
00949 0,
00950 FILE_ATTRIBUTE_NORMAL,
00951 INTERNAL_OPEN_ONLY,
00952 &info, &fsp);
00953 }
00954
00955 if (!NT_STATUS_IS_OK(status)) {
00956 return False;
00957 }
00958
00959
00960 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
00961 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
00962 close_file(fsp, NORMAL_CLOSE);
00963
00964
00965 if (!sd_size)
00966 return False;
00967
00968 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
00969 &access_granted, &status);
00970 }
00971
00972
00973
00974
00975
00976 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
00977 {
00978
00979
00980
00981
00982
00983 if (conn->admin_user)
00984 return False;
00985
00986
00987 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
00988 return True;
00989
00990 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
00991 return False;
00992
00993 return True;
00994 }
00995
00996
00997
00998
00999
01000 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
01001 {
01002 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
01003 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
01004 BOOL hide_special = lp_hide_special_files(SNUM(conn));
01005
01006 SET_STAT_INVALID(*pst);
01007
01008 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
01009 return True;
01010 }
01011
01012
01013 if (use_veto && IS_VETO_PATH(conn, name)) {
01014 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
01015 return False;
01016 }
01017
01018 if (hide_unreadable || hide_unwriteable || hide_special) {
01019 pstring link_target;
01020 char *entry = NULL;
01021
01022 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
01023 return False;
01024 }
01025
01026
01027 if (lp_host_msdfs() &&
01028 lp_msdfs_root(SNUM(conn)) &&
01029 is_msdfs_link(conn, entry, link_target, NULL)) {
01030 SAFE_FREE(entry);
01031 return True;
01032 }
01033
01034
01035 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
01036 DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
01037 SAFE_FREE(entry);
01038 return False;
01039 }
01040
01041 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
01042 DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
01043 SAFE_FREE(entry);
01044 return False;
01045 }
01046
01047 if (hide_special && file_is_special(conn, entry, pst)) {
01048 DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
01049 SAFE_FREE(entry);
01050 return False;
01051 }
01052 SAFE_FREE(entry);
01053 }
01054 return True;
01055 }
01056
01057
01058
01059
01060
01061 struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
01062 {
01063 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
01064
01065 if (!dirp) {
01066 return NULL;
01067 }
01068 ZERO_STRUCTP(dirp);
01069
01070 dirp->conn = conn;
01071 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
01072
01073 dirp->dir_path = SMB_STRDUP(name);
01074 if (!dirp->dir_path) {
01075 goto fail;
01076 }
01077 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
01078 if (!dirp->dir) {
01079 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
01080 goto fail;
01081 }
01082
01083 if (dirp->name_cache_size) {
01084 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry,
01085 dirp->name_cache_size);
01086 if (!dirp->name_cache) {
01087 goto fail;
01088 }
01089 } else {
01090 dirp->name_cache = NULL;
01091 }
01092
01093 dirhandles_open++;
01094 return dirp;
01095
01096 fail:
01097
01098 if (dirp) {
01099 if (dirp->dir) {
01100 SMB_VFS_CLOSEDIR(conn,dirp->dir);
01101 }
01102 SAFE_FREE(dirp->dir_path);
01103 SAFE_FREE(dirp->name_cache);
01104 SAFE_FREE(dirp);
01105 }
01106 return NULL;
01107 }
01108
01109
01110
01111
01112
01113
01114 int CloseDir(struct smb_Dir *dirp)
01115 {
01116 int i, ret = 0;
01117
01118 if (dirp->dir) {
01119 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
01120 }
01121 SAFE_FREE(dirp->dir_path);
01122 if (dirp->name_cache) {
01123 for (i = 0; i < dirp->name_cache_size; i++) {
01124 SAFE_FREE(dirp->name_cache[i].name);
01125 }
01126 }
01127 SAFE_FREE(dirp->name_cache);
01128 SAFE_FREE(dirp);
01129 dirhandles_open--;
01130 return ret;
01131 }
01132
01133
01134
01135
01136
01137
01138 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
01139 {
01140 const char *n;
01141 connection_struct *conn = dirp->conn;
01142
01143
01144 if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
01145 if (dirp->file_number == 0) {
01146 n = ".";
01147 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
01148 } else {
01149 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
01150 n = "..";
01151 }
01152 dirp->file_number++;
01153 return n;
01154 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
01155 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
01156 return NULL;
01157 } else {
01158
01159 SeekDir(dirp, *poffset);
01160 }
01161
01162 while ((n = vfs_readdirname(conn, dirp->dir))) {
01163
01164 if (*n == '.') {
01165 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
01166 continue;
01167 }
01168 }
01169 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
01170 dirp->file_number++;
01171 return n;
01172 }
01173 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
01174 return NULL;
01175 }
01176
01177
01178
01179
01180
01181 void RewindDir(struct smb_Dir *dirp, long *poffset)
01182 {
01183 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
01184 dirp->file_number = 0;
01185 dirp->offset = START_OF_DIRECTORY_OFFSET;
01186 *poffset = START_OF_DIRECTORY_OFFSET;
01187 }
01188
01189
01190
01191
01192
01193 void SeekDir(struct smb_Dir *dirp, long offset)
01194 {
01195 if (offset != dirp->offset) {
01196 if (offset == START_OF_DIRECTORY_OFFSET) {
01197 RewindDir(dirp, &offset);
01198
01199
01200
01201
01202
01203
01204
01205 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
01206 RewindDir(dirp, &offset);
01207
01208
01209
01210
01211
01212 dirp->file_number = 2;
01213 } else if (offset == END_OF_DIRECTORY_OFFSET) {
01214 ;
01215 } else {
01216 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
01217 }
01218 dirp->offset = offset;
01219 }
01220 }
01221
01222
01223
01224
01225
01226 long TellDir(struct smb_Dir *dirp)
01227 {
01228 return(dirp->offset);
01229 }
01230
01231
01232
01233
01234
01235 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
01236 {
01237 struct name_cache_entry *e;
01238
01239 if (!dirp->name_cache_size || !dirp->name_cache) {
01240 return;
01241 }
01242
01243 dirp->name_cache_index = (dirp->name_cache_index+1) %
01244 dirp->name_cache_size;
01245 e = &dirp->name_cache[dirp->name_cache_index];
01246 SAFE_FREE(e->name);
01247 e->name = SMB_STRDUP(name);
01248 e->offset = offset;
01249 }
01250
01251
01252
01253
01254
01255
01256 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
01257 {
01258 int i;
01259 const char *entry;
01260 connection_struct *conn = dirp->conn;
01261
01262
01263 if (dirp->name_cache_size && dirp->name_cache) {
01264 for (i = dirp->name_cache_index; i >= 0; i--) {
01265 struct name_cache_entry *e = &dirp->name_cache[i];
01266 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
01267 *poffset = e->offset;
01268 SeekDir(dirp, e->offset);
01269 return True;
01270 }
01271 }
01272 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
01273 struct name_cache_entry *e = &dirp->name_cache[i];
01274 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
01275 *poffset = e->offset;
01276 SeekDir(dirp, e->offset);
01277 return True;
01278 }
01279 }
01280 }
01281
01282
01283 SMB_VFS_REWINDDIR(conn, dirp->dir);
01284 dirp->file_number = 0;
01285 *poffset = START_OF_DIRECTORY_OFFSET;
01286 while ((entry = ReadDirName(dirp, poffset))) {
01287 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
01288 return True;
01289 }
01290 }
01291 return False;
01292 }
01293
01294
01295
01296
01297
01298 NTSTATUS can_delete_directory(struct connection_struct *conn,
01299 const char *dirname)
01300 {
01301 NTSTATUS status = NT_STATUS_OK;
01302 long dirpos = 0;
01303 const char *dname;
01304 struct smb_Dir *dir_hnd = OpenDir(conn, dirname, NULL, 0);
01305
01306 if (!dir_hnd) {
01307 return map_nt_error_from_unix(errno);
01308 }
01309
01310 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
01311 SMB_STRUCT_STAT st;
01312
01313
01314 if (dname[0] == '.') {
01315 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
01316 continue;
01317 }
01318 }
01319
01320 if (!is_visible_file(conn, dirname, dname, &st, True)) {
01321 continue;
01322 }
01323
01324 DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
01325 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
01326 break;
01327 }
01328 CloseDir(dir_hnd);
01329
01330 return status;
01331 }