/* * for some weird reason T2queryall() returns share names * in lower case so we have to do an extra test against * our share table to validate filename case. * * on top of this here (snell & Wilcox) most of our * redirections point to a share of the same name, * but some do not, thus the tail of the filename * returned by T2queryall() is not the same as * the name we wanted. * * We work around this by not validating the names * or files which resolve to share names as they must * be correct, having been enforced in the dfs layer. */ static int validfile(char *found, char *want, char *winpath, Share *sp) { char *share; if(strcmp(want, "..") == 0) return 1; if(strcmp(winpath, "/") == 0){ share = trimshare(sp->name); if(cistrcmp(want, share) == 0) return strcmp(want, share) == 0; /* * OK, a DFS redirection points us from a directory XXX * to a share named YYY. There is no case checking we can * do so we allow either case - it's all we can do. */ return 1; } if(cistrcmp(found, want) != 0) return 0; if(!Checkcase) return 1; if(strcmp(found, want) == 0) return 1; return 0; }
int mapshare(char *path, Share **osp) { int i; Share *sp; Dfscache *cp; char *s, *try; char *tail[] = { "", "$" }; if((cp = lookup(path, nil)) == nil) return 0; for(sp = Shares; sp < Shares+Nshares; sp++){ s = trimshare(sp->name); if(cistrcmp(cp->share, s) != 0) continue; if(Checkcase && strcmp(cp->share, s) != 0) continue; if(Debug && strstr(Debug, "dfs") != nil) print("mapshare, already connected, src=%q => dst=%q\n", path, sp->name); *osp = sp; return 0; } /* * Try to autoconnect to share if it is not known. Note even if you * didn't specify any shares and let the system autoconnect you may * not already have the share you need as RAP (which we use) throws * away names > 12 chars long. If we where to use RPC then this block * of code would be less important, though it would still be useful * to catch Shares added since cifs(1) was started. */ sp = Shares + Nshares; for(i = 0; i < 2; i++){ try = smprint("%s%s", cp->share, tail[i]); if(CIFStreeconnect(Sess, Sess->cname, try, sp) == 0){ sp->name = try; *osp = sp; Nshares++; if(Debug && strstr(Debug, "dfs") != nil) print("mapshare connected, src=%q dst=%q\n", path, cp->share); return 0; } free(try); } if(Debug && strstr(Debug, "dfs") != nil) print("mapshare failed src=%s\n", path); werrstr("not found"); return -1; }
/* * Rtt_tol is the fractional tollerance for RTT comparisons. * If a later (further down the list) host's RTT is less than * 1/Rtt_tol better than my current best then I don't bother * with it. This biases me towards entries at the top of the list * which Active Directory has already chosen for me and prevents * noise in RTTs from pushing me to more distant machines. */ static int remap(Dfscache *cp, Refer *re) { int n; int32_t rtt; char *p, *a[4]; enum { Hostname = 1, Sharename = 2, Pathname = 3, Rtt_tol = 10 }; if(Debug && strstr(Debug, "dfs") != nil) print(" remap %s\n", re->addr); for(p = re->addr; *p; p++) if(*p == '\\') *p = '/'; if(cp->prox < re->prox){ if(Debug && strstr(Debug, "dfs") != nil) print(" remap %d < %d\n", cp->prox, re->prox); return -1; } if((n = getfields(re->addr, a, sizeof(a), 0, "/")) < 3){ if(Debug && strstr(Debug, "dfs") != nil) print(" remap nfields=%d\n", n); return -1; } if((rtt = ping(a[Hostname], Dfstout)) == -1){ if(Debug && strstr(Debug, "dfs") != nil) print(" remap ping failed\n"); return -1; } if(cp->rtt < rtt && (rtt/labs(rtt-cp->rtt)) < Rtt_tol){ if(Debug && strstr(Debug, "dfs") != nil) print(" remap bad ping %ld < %ld && %ld < %d\n", cp->rtt, rtt, (rtt/labs(rtt-cp->rtt)), Rtt_tol); return -1; } if(n < 4) a[Pathname] = ""; if(re->ttl == 0) re->ttl = 60*5; free(cp->host); free(cp->share); free(cp->path); cp->rtt = rtt; cp->prox = re->prox; cp->expiry = time(nil)+re->ttl; cp->host = estrdup9p(a[Hostname]); cp->share = estrdup9p(trimshare(a[Sharename])); cp->path = estrdup9p(a[Pathname]); if(Debug && strstr(Debug, "dfs") != nil) print(" remap ping OK prox=%d host=%s share=%s path=%s\n", cp->prox, cp->host, cp->share, cp->path); return 0; }