bb0eec68015bf439f0ca33cde30935a7c8d2c143
[openafs.git] / src / WINNT / afsd / smb3.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #endif /* !DJGPP */
16 #include <stdlib.h>
17 #include <malloc.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <time.h>
21
22 #include <osi.h>
23
24 #include "afsd.h"
25
26 #include "smb.h"
27
28 extern smb_vc_t *dead_vcp;
29
30 extern osi_hyper_t hzero;
31
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
34
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
36
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
39
40 /* retrieve a held reference to a user structure corresponding to an incoming
41  * request */
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
43 {
44         smb_user_t *uidp;
45         cm_user_t *up;
46         
47         uidp = smb_FindUID(vcp, inp->uid, 0);
48         if (!uidp) return NULL;
49         
50         lock_ObtainMutex(&uidp->mx);
51         up = uidp->userp;
52         cm_HoldUser(up);
53         lock_ReleaseMutex(&uidp->mx);
54
55         smb_ReleaseUID(uidp);
56         
57         return up;
58 }
59
60 /*
61  * Return extended attributes.
62  * Right now, we aren't using any of the "new" bits, so this looks exactly
63  * like smb_Attributes() (see smb.c).
64  */
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
66 {
67         unsigned long attrs;
68
69         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70             || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
71                 attrs = 0x10;
72         else
73                 attrs = 0;
74         /*
75          * We used to mark a file RO if it was in an RO volume, but that
76          * turns out to be impolitic in NT.  See defect 10007.
77          */
78 #ifdef notdef
79         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
80 #endif
81         if ((scp->unixModeBits & 0222) == 0)
82                 attrs |= 1;             /* Read-only */
83
84         if (attrs == 0)
85                 attrs = 0x80;           /* FILE_ATTRIBUTE_NORMAL */
86
87         return attrs;
88 }
89
90 int smb_V3IsStarMask(char *maskp)
91 {
92         char tc;
93
94         while (tc = *maskp++)
95           if (tc == '?' || tc == '*') return 1;
96         return 0;
97 }
98
99 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
100 {
101         if (chainpp) {
102                 /* skip over null-terminated string */
103                 *chainpp = inp + strlen(inp) + 1;
104         }
105         return inp;
106 }
107
108 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
109 {
110         char *tp;
111         char *usern, *pwd, *pwdx;
112         smb_user_t *uidp, *dead_uidp;
113         unsigned short newUid;
114         unsigned long caps;
115         cm_user_t *userp;
116         char *s1 = " ";
117
118         /* Check for bad conns */
119         if (vcp->flags & SMB_VCFLAG_REMOTECONN)
120                 return CM_ERROR_REMOTECONN;
121
122         /* For NT LM 0.12 and up, get capabilities */
123         if (vcp->flags & SMB_VCFLAG_USENT) {
124                 caps = smb_GetSMBParm(inp, 11);
125                 if (caps & 0x40)
126                         vcp->flags |= SMB_VCFLAG_STATUS32;
127                 /* for now, ignore other capability bits */
128         }
129
130         /* Parse the data */
131         tp = smb_GetSMBData(inp, NULL);
132         if (vcp->flags & SMB_VCFLAG_USENT)
133                 pwdx = smb_ParseString(tp, &tp);
134         pwd = smb_ParseString(tp, &tp);
135         usern = smb_ParseString(tp, &tp);
136
137         /* Create a new UID and cm_user_t structure */
138         userp = cm_NewUser();
139         lock_ObtainMutex(&vcp->mx);
140         newUid = vcp->uidCounter++;
141         lock_ReleaseMutex(&vcp->mx);
142
143         /* Create a new smb_user_t structure and connect them up */
144         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
145         lock_ObtainMutex(&uidp->mx);
146         uidp->userp = userp;
147         uidp->name = strdup(usern);
148         lock_ReleaseMutex(&uidp->mx);
149         smb_ReleaseUID(uidp);
150         
151         if (dead_vcp) {
152                 dead_uidp = dead_vcp->usersp;
153                 while (dead_uidp) {
154                         if (dead_uidp->userp
155                             && strcmp(dead_uidp->name, usern) == 0)
156                                 break;
157                         dead_uidp = dead_uidp->nextp;
158                 }
159         }
160
161         /* transfer tokens from dead vcp */
162         if (dead_vcp && dead_uidp) {
163                 cm_user_t *dead_userp;
164                 s1 = ", tokens from terminated session";
165                 dead_userp = dead_uidp->userp;
166                 cm_ResetACLCache(dead_userp);
167                 userp->cellInfop = dead_userp->cellInfop;
168                 dead_userp->cellInfop = NULL;
169                 dead_vcp = NULL;
170         }
171
172         /* transfer tokens from integrated logon */
173         if (vcp->logonDLLUser) {
174                 s1 = ", tokens from integrated logon";
175                 cm_ResetACLCache(vcp->logonDLLUser);
176                 userp->cellInfop = vcp->logonDLLUser->cellInfop;
177                 vcp->logonDLLUser->cellInfop = NULL;
178                 vcp->logonDLLUser = NULL;
179         }
180
181         /* transfer tokens for logoff profile upload */
182         if (vcp->justLoggedOut) {
183                 cm_user_t *logout_userp;
184                 if (GetTickCount() - vcp->logoffTime <
185                         1000 * smb_LogoffTransferTimeout
186                     && strcmp(vcp->justLoggedOut->name, usern) == 0) {
187                         s1 = ", tokens from logoff";
188                         logout_userp = vcp->justLoggedOut->userp;
189                         cm_ResetACLCache(logout_userp);
190                         userp->cellInfop = logout_userp->cellInfop;
191                         logout_userp->cellInfop = NULL;
192                 }
193                 vcp->justLoggedOut = NULL;
194         }
195         else if (loggedOut) {
196                 cm_user_t *logout_userp;
197                 if (GetTickCount() - loggedOutTime <
198                         1000 * smb_LogoffTransferTimeout
199                     && strcmp(loggedOutName, usern) == 0) {
200                         s1 = ", tokens from logoff";
201                         logout_userp = loggedOutUserp->userp;
202                         cm_ResetACLCache(logout_userp);
203                         userp->cellInfop = logout_userp->cellInfop;
204                         logout_userp->cellInfop = NULL;
205                 }
206                 smb_ReleaseUID(loggedOutUserp);
207                 loggedOutUserp = NULL;
208                 free(loggedOutName);
209                 loggedOutName = NULL;
210                 loggedOut = 0;
211         }
212
213         /* Return UID to the client */
214         ((smb_t *)outp)->uid = newUid;
215         /* Also to the next chained message */
216         ((smb_t *)inp)->uid = newUid;
217
218         osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
219                         osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
220         smb_SetSMBParm(outp, 2, 0);
221         smb_SetSMBDataLength(outp, 0);
222         return 0;
223 }
224
225 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
226 {
227         smb_user_t *uidp;
228
229         /* don't get tokens from this VC */
230         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
231
232         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
233
234         /* find the tree and free it */
235         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
236         if (uidp) {
237                 char *s1 = NULL, *s2 = NULL;
238
239                 /* Also, this is not logon session any more */
240                 if (uidp->userp == vcp->logonDLLUser) {
241                         s1 = ", was logon session";
242                         vcp->logonDLLUser = NULL;
243                 }
244
245                 /* But its tokens might be needed later */
246                 if (uidp->userp && !(uidp->userp->flags & CM_USERFLAG_WASLOGON)
247                     && smb_LogoffTokenTransfer) {
248                         s2 = ", pre-logout effect";
249                         vcp->justLoggedOut = uidp;
250                         vcp->logoffTime = GetTickCount();
251                 }
252
253                 if (s2 == NULL) s2 = " ";
254                 if (s1 == NULL) {s1 = s2; s2 = " ";}
255
256                 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
257                          uidp->userID,
258                          osi_LogSaveString(afsd_logp, uidp->name),
259                          s1, s2);
260
261                 lock_ObtainMutex(&uidp->mx);
262                 uidp->flags |= SMB_USERFLAG_DELETE;
263                 /*
264                  * it doesn't get deleted right away
265                  * because the vcp points to it
266                  */
267                 lock_ReleaseMutex(&uidp->mx);
268         }
269         else
270                 osi_Log0(afsd_logp, "SMB3 user logoffX");
271
272         smb_SetSMBDataLength(outp, 0);
273         return 0;
274 }
275
276 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
277 {
278         smb_tid_t *tidp;
279         unsigned short newTid;
280         char shareName[256];
281         char *sharePath;
282         int shareFound;
283         char *tp;
284         char *pathp;
285         char *passwordp;
286         char *servicep;
287         cm_user_t *userp;
288         
289         osi_Log0(afsd_logp, "SMB3 receive tree connect");
290
291         /* parse input parameters */
292         tp = smb_GetSMBData(inp, NULL);
293         passwordp = smb_ParseString(tp, &tp);
294         pathp = smb_ParseString(tp, &tp);
295         servicep = smb_ParseString(tp, &tp);
296
297         tp = strrchr(pathp, '\\');
298         if (!tp) {
299                 return CM_ERROR_BADSMB;
300         }
301         strcpy(shareName, tp+1);
302
303         if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
304                 return CM_ERROR_NOIPC;
305
306         userp = smb_GetUser(vcp, inp);
307
308         lock_ObtainMutex(&vcp->mx);
309         newTid = vcp->tidCounter++;
310         lock_ReleaseMutex(&vcp->mx);
311         
312         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
313         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
314         if (!shareFound) {
315                 smb_ReleaseTID(tidp);
316                 return CM_ERROR_BADSHARENAME;
317         }
318         lock_ObtainMutex(&tidp->mx);
319         tidp->userp = userp;
320         tidp->pathname = sharePath;
321         lock_ReleaseMutex(&tidp->mx);
322         smb_ReleaseTID(tidp);
323
324         if (vcp->flags & SMB_VCFLAG_USENT)
325                 smb_SetSMBParm(outp, 2, 0);     /* OptionalSupport bits */
326
327         ((smb_t *)outp)->tid = newTid;
328         ((smb_t *)inp)->tid = newTid;
329         tp = smb_GetSMBData(outp, NULL);
330         *tp++ = 'A';
331         *tp++ = ':';
332         *tp++ = 0;
333         smb_SetSMBDataLength(outp, 3);
334         
335         osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
336         return 0;
337 }
338
339 /* must be called with global tran lock held */
340 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
341 {
342         smb_tran2Packet_t *tp;
343         smb_t *smbp;
344         
345         smbp = (smb_t *) inp->data;
346         for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
347                 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
348                         return tp;
349         }
350         return NULL;
351 }
352
353 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
354         int totalParms, int totalData)
355 {
356         smb_tran2Packet_t *tp;
357         smb_t *smbp;
358         
359         smbp = (smb_t *) inp->data;
360         tp = malloc(sizeof(*tp));
361         memset(tp, 0, sizeof(*tp));
362         tp->vcp = vcp;
363         smb_HoldVC(vcp);
364         tp->curData = tp->curParms = 0;
365         tp->totalData = totalData;
366         tp->totalParms = totalParms;
367         tp->tid = smbp->tid;
368         tp->mid = smbp->mid;
369         tp->uid = smbp->uid;
370         tp->pid = smbp->pid;
371         tp->res[0] = smbp->res[0];
372         osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
373         tp->opcode = smb_GetSMBParm(inp, 14);
374         if (totalParms != 0)
375                 tp->parmsp = malloc(totalParms);
376         if (totalData != 0)
377                 tp->datap = malloc(totalData);
378         tp->flags |= SMB_TRAN2PFLAG_ALLOC;
379         return tp;
380 }
381
382 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
383         smb_tran2Packet_t *inp, smb_packet_t *outp,
384         int totalParms, int totalData)
385 {
386         smb_tran2Packet_t *tp;
387         unsigned short parmOffset;
388         unsigned short dataOffset;
389         unsigned short dataAlign;
390         
391         tp = malloc(sizeof(*tp));
392         memset(tp, 0, sizeof(*tp));
393         tp->vcp = NULL;
394         tp->curData = tp->curParms = 0;
395         tp->totalData = totalData;
396         tp->totalParms = totalParms;
397         tp->oldTotalParms = totalParms;
398         tp->tid = inp->tid;
399         tp->mid = inp->mid;
400         tp->uid = inp->uid;
401         tp->pid = inp->pid;
402         tp->res[0] = inp->res[0];
403         tp->opcode = inp->opcode;
404
405         /*
406          * We calculate where the parameters and data will start.
407          * This calculation must parallel the calculation in
408          * smb_SendTran2Packet.
409          */
410
411         parmOffset = 10*2 + 35;
412         parmOffset++;                   /* round to even */
413         tp->parmsp = (unsigned short *) (outp->data + parmOffset);
414
415         dataOffset = parmOffset + totalParms;
416         dataAlign = dataOffset & 2;     /* quad-align */
417         dataOffset += dataAlign;
418         tp->datap = outp->data + dataOffset;
419
420         return tp;
421 }
422
423 /* free a tran2 packet; must be called with smb_globalLock held */
424 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
425 {
426         if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
427         if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
428                 if (t2p->parmsp)
429                         free(t2p->parmsp);
430                 if (t2p->datap)
431                         free(t2p->datap);
432         }
433         free(t2p);
434 }
435
436 /* called with a VC, an input packet to respond to, and an error code.
437  * sends an error response.
438  */
439 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
440         smb_packet_t *tp, long code)
441 {
442         smb_t *smbp;
443         unsigned short errCode;
444         unsigned char errClass;
445         unsigned long NTStatus;
446
447         if (vcp->flags & SMB_VCFLAG_STATUS32)
448                 smb_MapNTError(code, &NTStatus);
449         else
450                 smb_MapCoreError(code, vcp, &errCode, &errClass);
451
452         smb_FormatResponsePacket(vcp, NULL, tp);
453         smbp = (smb_t *) tp;
454         
455         /* We can handle long names */
456         if (vcp->flags & SMB_VCFLAG_USENT)
457                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
458         
459         /* now copy important fields from the tran 2 packet */
460         smbp->com = 0x32;               /* tran 2 response */
461         smbp->tid = t2p->tid;
462         smbp->mid = t2p->mid;
463         smbp->pid = t2p->pid;
464         smbp->uid = t2p->uid;
465         smbp->res[0] = t2p->res[0];
466         if (vcp->flags & SMB_VCFLAG_STATUS32) {
467                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
468                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
469                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
470                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
471                 smbp->flg2 |= 0x4000;
472         }
473         else {
474                 smbp->rcls = errClass;
475                 smbp->errLow = (unsigned char) (errCode & 0xff);
476                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
477         }
478         
479         /* send packet */
480         smb_SendPacket(vcp, tp);
481 }        
482
483 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
484 {
485         smb_t *smbp;
486         unsigned short parmOffset;
487         unsigned short dataOffset;
488         unsigned short totalLength;
489         unsigned short dataAlign;
490         char *datap;
491         
492         smb_FormatResponsePacket(vcp, NULL, tp);
493         smbp = (smb_t *) tp;
494
495         /* We can handle long names */
496         if (vcp->flags & SMB_VCFLAG_USENT)
497                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
498         
499         /* now copy important fields from the tran 2 packet */
500         smbp->com = 0x32;               /* tran 2 response */
501         smbp->tid = t2p->tid;
502         smbp->mid = t2p->mid;
503         smbp->pid = t2p->pid;
504         smbp->uid = t2p->uid;
505         smbp->res[0] = t2p->res[0];
506
507         totalLength = 1 + t2p->totalData + t2p->totalParms;
508
509         /* now add the core parameters (tran2 info) to the packet */
510         smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
511         smb_SetSMBParm(tp, 1, t2p->totalData);  /* data bytes */
512         smb_SetSMBParm(tp, 2, 0);               /* reserved */
513         smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
514         parmOffset = 10*2 + 35;                 /* parm offset in packet */
515         parmOffset++;                           /* round to even */
516         smb_SetSMBParm(tp, 4, parmOffset);      /* 11 parm words plus *
517                                                  * hdr, bcc and wct */
518         smb_SetSMBParm(tp, 5, 0);               /* parm displacement */
519         smb_SetSMBParm(tp, 6, t2p->totalData);  /* data in this packet */
520         dataOffset = parmOffset + t2p->oldTotalParms;
521         dataAlign = dataOffset & 2;             /* quad-align */
522         dataOffset += dataAlign;
523         smb_SetSMBParm(tp, 7, dataOffset);      /* offset of data */
524         smb_SetSMBParm(tp, 8, 0);               /* data displacement */
525         smb_SetSMBParm(tp, 9, 0);               /* low: setup word count *
526                                                  * high: resvd */
527         
528         datap = smb_GetSMBData(tp, NULL);
529         *datap++ = 0;                           /* we rounded to even */
530
531         totalLength += dataAlign;
532         smb_SetSMBDataLength(tp, totalLength);
533         
534         /* next, send the datagram */
535         smb_SendPacket(vcp, tp);
536 }
537
538 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
539 {
540         smb_tran2Packet_t *asp;
541         int totalParms;
542         int totalData;
543         int parmDisp;
544         int dataDisp;
545         int parmOffset;
546         int dataOffset;
547         int parmCount;
548         int dataCount;
549         int firstPacket;
550         long code;
551
552         /* We sometimes see 0 word count.  What to do? */
553         if (*inp->wctp == 0) {
554 #ifndef DJGPP
555                 HANDLE h;
556                 char *ptbuf[1];
557
558                 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0"); 
559
560                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
561                 ptbuf[0] = "Transaction2 word count = 0";
562                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
563                             1, inp->ncb_length, ptbuf, inp);
564                 DeregisterEventSource(h);
565 #else /* DJGPP */
566                 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0"); 
567 #endif /* !DJGPP */
568
569                 smb_SetSMBDataLength(outp, 0);
570                 smb_SendPacket(vcp, outp);
571                 return 0;
572         }
573
574         totalParms = smb_GetSMBParm(inp, 0);
575         totalData = smb_GetSMBParm(inp, 1);
576         
577         firstPacket = (inp->inCom == 0x32);
578         
579         /* find the packet we're reassembling */
580         lock_ObtainWrite(&smb_globalLock);
581         asp = smb_FindTran2Packet(vcp, inp);
582         if (!asp) {
583                 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
584         }
585         lock_ReleaseWrite(&smb_globalLock);
586         
587         /* now merge in this latest packet; start by looking up offsets */
588         if (firstPacket) {
589                 parmDisp = dataDisp = 0;
590                 parmOffset = smb_GetSMBParm(inp, 10);
591                 dataOffset = smb_GetSMBParm(inp, 12);
592                 parmCount = smb_GetSMBParm(inp, 9);
593                 dataCount = smb_GetSMBParm(inp, 11);
594                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
595                 asp->maxReturnData = smb_GetSMBParm(inp, 3);
596
597                 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
598                         totalData, dataCount, asp->maxReturnData);
599         }
600         else {
601                 parmDisp = smb_GetSMBParm(inp, 4);
602                 parmOffset = smb_GetSMBParm(inp, 3);
603                 dataDisp = smb_GetSMBParm(inp, 7);
604                 dataOffset = smb_GetSMBParm(inp, 6);
605                 parmCount = smb_GetSMBParm(inp, 2);
606                 dataCount = smb_GetSMBParm(inp, 5);
607                 
608                 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
609                         parmCount, dataCount);
610         }
611
612         /* now copy the parms and data */
613         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
614         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
615         
616         /* account for new bytes */
617         asp->curData += dataCount;
618         asp->curParms += parmCount;
619         
620         /* finally, if we're done, remove the packet from the queue and dispatch it */
621         if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
622                 /* we've received it all */
623                 lock_ObtainWrite(&smb_globalLock);
624                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
625                 lock_ReleaseWrite(&smb_globalLock);
626                 
627                 /* now dispatch it */
628                 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
629
630                 /* if an error is returned, we're supposed to send an error packet,
631                  * otherwise the dispatched function already did the data sending.
632                  * We give dispatched proc the responsibility since it knows how much
633                  * space to allocate.
634                  */
635                 if (code != 0) {
636                         smb_SendTran2Error(vcp, asp, outp, code);
637                 }
638
639                 /* free the input tran 2 packet */
640                 lock_ObtainWrite(&smb_globalLock);
641                 smb_FreeTran2Packet(asp);
642                 lock_ReleaseWrite(&smb_globalLock);
643         }
644         else if (firstPacket) {
645                 /* the first packet in a multi-packet request, we need to send an
646                  * ack to get more data.
647                  */
648                 smb_SetSMBDataLength(outp, 0);
649                 smb_SendPacket(vcp, outp);
650         }
651
652         return 0;
653 }
654
655 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
656 {
657         char *pathp;
658         smb_tran2Packet_t *outp;
659         long code;
660         cm_space_t *spacep;
661         int excl;
662         cm_user_t *userp;
663         cm_scache_t *dscp;              /* dir we're dealing with */
664         cm_scache_t *scp;               /* file we're creating */
665         cm_attr_t setAttr;
666         int initialModeBits;
667         smb_fid_t *fidp;
668         int attributes;
669         char *lastNamep;
670         long dosTime;
671         int openFun;
672         int trunc;
673         int openMode;
674         int extraInfo;
675         int openAction;
676         int parmSlot;                   /* which parm we're dealing with */
677         long returnEALength;
678         char *tidPathp;
679         cm_req_t req;
680
681         cm_InitReq(&req);
682
683         scp = NULL;
684         
685         extraInfo = (p->parmsp[0] & 1); /* return extra info */
686         returnEALength = (p->parmsp[0] & 8);    /* return extended attr length */
687
688         openFun = p->parmsp[6];         /* open function */
689         excl = ((openFun & 3) == 0);
690         trunc = ((openFun & 3) == 2);   /* truncate it */
691         openMode = (p->parmsp[1] & 0x7);
692         openAction = 0;                 /* tracks what we did */
693
694         attributes = p->parmsp[3];
695         dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
696         
697         /* compute initial mode bits based on read-only flag in attributes */
698         initialModeBits = 0666;
699         if (attributes & 1) initialModeBits &= ~0222;
700         
701         pathp = (char *) (&p->parmsp[14]);
702         
703         outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
704
705         spacep = cm_GetSpace();
706         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
707
708         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
709                 /* special case magic file name for receiving IOCTL requests
710                  * (since IOCTL calls themselves aren't getting through).
711                  */
712                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
713                 smb_SetupIoctlFid(fidp, spacep);
714
715                 /* copy out remainder of the parms */
716                 parmSlot = 0;
717                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
718                 if (extraInfo) {
719                         outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
720                         outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
721                         outp->parmsp[parmSlot] = 0; parmSlot++;
722                         outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
723                         outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
724                         outp->parmsp[parmSlot] = openMode; parmSlot++;
725                         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
726                         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
727                 }
728                 /* and the final "always present" stuff */
729                 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
730                 /* next write out the "unique" ID */
731                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
732                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
733                 outp->parmsp[parmSlot] = 0; parmSlot++;
734                 if (returnEALength) {
735                         outp->parmsp[parmSlot] = 0; parmSlot++;
736                         outp->parmsp[parmSlot] = 0; parmSlot++;
737                 }
738                 
739                 outp->totalData = 0;
740                 outp->totalParms = parmSlot * 2;
741                 
742                 smb_SendTran2Packet(vcp, outp, op);
743                 
744                 smb_FreeTran2Packet(outp);
745
746                 /* and clean up fid reference */
747                 smb_ReleaseFID(fidp);
748                 return 0;
749         }
750
751         userp = smb_GetTran2User(vcp, p);
752         tidPathp = smb_GetTIDPath(vcp, p->tid);
753
754         dscp = NULL;
755         code = cm_NameI(cm_rootSCachep, pathp,
756                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
757                         userp, tidPathp, &req, &scp);
758         if (code != 0) {
759                 code = cm_NameI(cm_rootSCachep, spacep->data,
760                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
761                         userp, tidPathp, &req, &dscp);
762                 cm_FreeSpace(spacep);
763
764                 if (code) {
765                         cm_ReleaseUser(userp);
766                         smb_FreeTran2Packet(outp);
767                         return code;
768                 }
769         
770                 /* otherwise, scp points to the parent directory.  Do a lookup,
771                  * and truncate the file if we find it, otherwise we create the
772                  * file.
773                  */
774                 if (!lastNamep) lastNamep = pathp;
775                 else lastNamep++;
776                 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
777                                  &req, &scp);
778                 if (code && code != CM_ERROR_NOSUCHFILE) {
779                         cm_ReleaseSCache(dscp);
780                         cm_ReleaseUser(userp);
781                         smb_FreeTran2Packet(outp);
782                         return code;
783                 }
784         }
785         else {
786                 cm_FreeSpace(spacep);
787         }
788         
789         /* if we get here, if code is 0, the file exists and is represented by
790          * scp.  Otherwise, we have to create it.
791          */
792         if (code == 0) {
793                 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
794                 if (code) {
795                         if (dscp) cm_ReleaseSCache(dscp);
796                         cm_ReleaseSCache(scp);
797                         cm_ReleaseUser(userp);
798                         smb_FreeTran2Packet(outp);
799                         return code;
800                 }
801
802                 if (excl) {
803                         /* oops, file shouldn't be there */
804                         if (dscp) cm_ReleaseSCache(dscp);
805                         cm_ReleaseSCache(scp);
806                         cm_ReleaseUser(userp);
807                         smb_FreeTran2Packet(outp);
808                         return CM_ERROR_EXISTS;
809                 }
810
811                 if (trunc) {
812                         setAttr.mask = CM_ATTRMASK_LENGTH;
813                         setAttr.length.LowPart = 0;
814                         setAttr.length.HighPart = 0;
815                         code = cm_SetAttr(scp, &setAttr, userp, &req);
816                         openAction = 3; /* truncated existing file */
817                 }
818                 else openAction = 1;    /* found existing file */
819         }
820         else if (!(openFun & 0x10)) {
821                 /* don't create if not found */
822                 if (dscp) cm_ReleaseSCache(dscp);
823                 osi_assert(scp == NULL);
824                 cm_ReleaseUser(userp);
825                 smb_FreeTran2Packet(outp);
826                 return CM_ERROR_NOSUCHFILE;
827         }
828         else {
829                 osi_assert(dscp != NULL && scp == NULL);
830                 openAction = 2; /* created file */
831                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
832                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
833                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
834                                  &req);
835                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
836                         smb_NotifyChange(FILE_ACTION_ADDED,
837                                          FILE_NOTIFY_CHANGE_FILE_NAME,
838                                          dscp, lastNamep, NULL, TRUE);
839                 if (!excl && code == CM_ERROR_EXISTS) {
840                         /* not an exclusive create, and someone else tried
841                          * creating it already, then we open it anyway.  We
842                          * don't bother retrying after this, since if this next
843                          * fails, that means that the file was deleted after we
844                          * started this call.
845                          */
846                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
847                                          userp, &req, &scp);
848                         if (code == 0) {
849                                 if (trunc) {
850                                         setAttr.mask = CM_ATTRMASK_LENGTH;
851                                         setAttr.length.LowPart = 0;
852                                         setAttr.length.HighPart = 0;
853                                         code = cm_SetAttr(scp, &setAttr, userp,
854                                                           &req);
855                                 }
856                         }       /* lookup succeeded */
857                 }
858         }
859         
860         /* we don't need this any longer */
861         if (dscp) cm_ReleaseSCache(dscp);
862
863         if (code) {
864                 /* something went wrong creating or truncating the file */
865                 if (scp) cm_ReleaseSCache(scp);
866                 cm_ReleaseUser(userp);
867                 smb_FreeTran2Packet(outp);
868                 return code;
869         }
870         
871         /* make sure we're about to open a file */
872         if (scp->fileType != CM_SCACHETYPE_FILE) {
873                 cm_ReleaseSCache(scp);
874                 cm_ReleaseUser(userp);
875                 smb_FreeTran2Packet(outp);
876                 return CM_ERROR_ISDIR;
877         }
878
879         /* now all we have to do is open the file itself */
880         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
881         osi_assert(fidp);
882         
883         /* save a pointer to the vnode */
884         fidp->scp = scp;
885         
886         /* compute open mode */
887         if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
888         if (openMode == 1 || openMode == 2)
889                 fidp->flags |= SMB_FID_OPENWRITE;
890
891         smb_ReleaseFID(fidp);
892         
893         cm_Open(scp, 0, userp);
894
895         /* copy out remainder of the parms */
896         parmSlot = 0;
897         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
898         lock_ObtainMutex(&scp->mx);
899         if (extraInfo) {
900                 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
901                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
902                 outp->parmsp[parmSlot] =  dosTime & 0xffff; parmSlot++;
903                 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
904                 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
905                         parmSlot++;
906                 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
907                         parmSlot++;
908                 outp->parmsp[parmSlot] = openMode; parmSlot++;
909                 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
910                 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
911         }
912         /* and the final "always present" stuff */
913         outp->parmsp[parmSlot] = openAction; parmSlot++;
914         /* next write out the "unique" ID */
915         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
916         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
917         outp->parmsp[parmSlot] = 0; parmSlot++;
918         if (returnEALength) {
919                 outp->parmsp[parmSlot] = 0; parmSlot++;
920                 outp->parmsp[parmSlot] = 0; parmSlot++;
921         }
922         lock_ReleaseMutex(&scp->mx);
923         outp->totalData = 0;            /* total # of data bytes */
924         outp->totalParms = parmSlot * 2;        /* shorts are two bytes */
925
926         smb_SendTran2Packet(vcp, outp, op);
927         
928         smb_FreeTran2Packet(outp);
929
930         cm_ReleaseUser(userp);
931         /* leave scp held since we put it in fidp->scp */
932         return 0;
933 }
934
935 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 {
937         return CM_ERROR_BADOP;
938 }
939
940 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
941 {
942         return CM_ERROR_BADOP;
943 }
944
945 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
946 {
947         smb_tran2Packet_t *outp;
948         smb_tran2QFSInfo_t qi;
949         int responseSize;
950         osi_hyper_t temp;
951         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
952         
953         osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
954
955         switch (p->parmsp[0]) {
956         case 1: responseSize = sizeof(qi.u.allocInfo); break;
957         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
958         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
959         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
960         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
961         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
962         default: return CM_ERROR_INVAL;
963         }
964
965         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
966         switch (p->parmsp[0]) {
967         case 1:
968                 /* alloc info */
969                 qi.u.allocInfo.FSID = 0;
970                 qi.u.allocInfo.sectorsPerAllocUnit = 1;
971                 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
972                 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
973                 qi.u.allocInfo.bytesPerSector = 1024;
974                 break;
975
976         case 2:
977                 /* volume info */
978                 qi.u.volumeInfo.vsn = 1234;
979                 qi.u.volumeInfo.vnCount = 4;
980                 /* we're supposed to pad it out with zeroes to the end */
981                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
982                 strcpy(qi.u.volumeInfo.label, "AFS");
983                 break;
984
985         case 0x102:
986                 /* FS volume info */
987                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
988                 qi.u.FSvolumeInfo.vsn = 1234;
989                 qi.u.FSvolumeInfo.vnCount = 4;
990                 strcpy(qi.u.FSvolumeInfo.label, "AFS");
991                 break;
992
993         case 0x103:
994                 /* FS size info */
995                 temp.HighPart = 0;
996                 temp.LowPart = 0x7fffffff;
997                 qi.u.FSsizeInfo.totalAllocUnits = temp;
998                 temp.LowPart = 0x3fffffff;
999                 qi.u.FSsizeInfo.availAllocUnits = temp;
1000                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1001                 qi.u.FSsizeInfo.bytesPerSector = 1024;
1002                 break;
1003
1004         case 0x104:
1005                 /* FS device info */
1006                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
1007                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1008                 break;
1009
1010         case 0x105:
1011                 /* FS attribute info */
1012                 /* attributes, defined in WINNT.H:
1013                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
1014                  *      FILE_CASE_PRESERVED_NAMES       0x2
1015                  *      <no name defined>               0x4000
1016                  *         If bit 0x4000 is not set, Windows 95 thinks
1017                  *         we can't handle long (non-8.3) names,
1018                  *         despite our protestations to the contrary.
1019                  */
1020                 qi.u.FSattributeInfo.attributes = 0x4003;
1021                 qi.u.FSattributeInfo.maxCompLength = 255;
1022                 qi.u.FSattributeInfo.FSnameLength = 6;
1023                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1024                 break;
1025         }
1026         
1027         /* copy out return data, and set corresponding sizes */
1028         outp->totalParms = 0;
1029         outp->totalData = responseSize;
1030         memcpy(outp->datap, &qi, responseSize);
1031
1032         /* send and free the packets */
1033         smb_SendTran2Packet(vcp, outp, op);
1034         smb_FreeTran2Packet(outp);
1035
1036         return 0;
1037 }
1038
1039 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1040 {
1041         return CM_ERROR_BADOP;
1042 }
1043
1044 struct smb_ShortNameRock {
1045         char *maskp;
1046         unsigned int vnode;
1047         char *shortName;
1048         size_t shortNameLen;
1049 };
1050
1051 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1052         osi_hyper_t *offp)
1053 {
1054         struct smb_ShortNameRock *rockp;
1055         char *shortNameEnd;
1056
1057         rockp = vrockp;
1058         /* compare both names and vnodes, though probably just comparing vnodes
1059          * would be safe enough.
1060          */
1061         if (stricmp(dep->name, rockp->maskp) != 0)
1062                 return 0;
1063         if (ntohl(dep->fid.vnode) != rockp->vnode)
1064                 return 0;
1065         /* This is the entry */
1066         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1067         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1068         return CM_ERROR_STOPNOW;
1069 }
1070
1071 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1072         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1073 {
1074         struct smb_ShortNameRock rock;
1075         char *lastNamep;
1076         cm_space_t *spacep;
1077         cm_scache_t *dscp;
1078         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1079         long code;
1080         osi_hyper_t thyper;
1081
1082         spacep = cm_GetSpace();
1083         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1084
1085         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1086                         reqp, &dscp);
1087         cm_FreeSpace(spacep);
1088         if (code) return code;
1089
1090         if (!lastNamep) lastNamep = pathp;
1091         else lastNamep++;
1092         thyper.LowPart = 0;
1093         thyper.HighPart = 0;
1094         rock.shortName = shortName;
1095         rock.vnode = vnode;
1096         rock.maskp = lastNamep;
1097         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1098                            reqp, NULL);
1099
1100         cm_ReleaseSCache(dscp);
1101
1102         if (code == 0)
1103                 return CM_ERROR_NOSUCHFILE;
1104         if (code == CM_ERROR_STOPNOW) {
1105                 *shortNameLenp = rock.shortNameLen;
1106                 return 0;
1107         }
1108         return code;
1109 }
1110
1111 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1112 {
1113         smb_tran2Packet_t *outp;
1114         unsigned long dosTime;
1115         FILETIME ft;
1116         unsigned short infoLevel;
1117         int nbytesRequired;
1118         unsigned short attributes;
1119         unsigned long extAttributes;
1120         char shortName[13];
1121         unsigned int len;
1122         cm_user_t *userp;
1123         cm_space_t *spacep;
1124         cm_scache_t *scp, *dscp;
1125         long code;
1126         char *op;
1127         char *tidPathp;
1128         char *lastComp;
1129         cm_req_t req;
1130
1131         cm_InitReq(&req);
1132
1133         infoLevel = p->parmsp[0];
1134         if (infoLevel == 6) nbytesRequired = 0;
1135         else if (infoLevel == 1) nbytesRequired = 22;
1136         else if (infoLevel == 2) nbytesRequired = 26;
1137         else if (infoLevel == 0x101) nbytesRequired = 40;
1138         else if (infoLevel == 0x102) nbytesRequired = 24;
1139         else if (infoLevel == 0x103) nbytesRequired = 4;
1140         else if (infoLevel == 0x108) nbytesRequired = 30;
1141         else {
1142                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1143                          p->opcode, infoLevel);
1144                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1145                 return 0;
1146         }
1147         osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1148                  osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1149
1150         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1151
1152         if (infoLevel > 0x100)
1153                 outp->totalParms = 2;
1154         else
1155                 outp->totalParms = 0;
1156         outp->totalData = nbytesRequired;
1157         
1158         /* now, if we're at infoLevel 6, we're only being asked to check
1159          * the syntax, so we just OK things now.  In particular, we're *not*
1160          * being asked to verify anything about the state of any parent dirs.
1161          */
1162         if (infoLevel == 6) {
1163                 smb_SendTran2Packet(vcp, outp, opx);
1164                 smb_FreeTran2Packet(outp);
1165                 return 0;
1166         }
1167         
1168         userp = smb_GetTran2User(vcp, p);
1169
1170         tidPathp = smb_GetTIDPath(vcp, p->tid);
1171
1172         /*
1173          * XXX Strange hack XXX
1174          *
1175          * As of Patch 7 (13 January 98), we are having the following problem:
1176          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177          * requests to look up "desktop.ini" in all the subdirectories.
1178          * This can cause zillions of timeouts looking up non-existent cells
1179          * and volumes, especially in the top-level directory.
1180          *
1181          * We have not found any way to avoid this or work around it except
1182          * to explicitly ignore the requests for mount points that haven't
1183          * yet been evaluated and for directories that haven't yet been
1184          * fetched.
1185          */
1186         if (infoLevel == 0x101) {
1187                 spacep = cm_GetSpace();
1188                 smb_StripLastComponent(spacep->data, &lastComp,
1189                                         (char *)(&p->parmsp[3]));
1190                 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1191                         code = cm_NameI(cm_rootSCachep, spacep->data,
1192                                         CM_FLAG_CASEFOLD
1193                                           | CM_FLAG_DIRSEARCH
1194                                           | CM_FLAG_FOLLOW,
1195                                         userp, tidPathp, &req, &dscp);
1196                         if (code == 0) {
1197                                 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1198                                     && !dscp->mountRootFidp)
1199                                         code = CM_ERROR_NOSUCHFILE;
1200                                 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1201                                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1202                                         if (bp)
1203                                                 buf_Release(bp);
1204                                         else
1205                                                 code = CM_ERROR_NOSUCHFILE;
1206                                 }
1207                                 cm_ReleaseSCache(dscp);
1208                                 if (code) {
1209                                         cm_FreeSpace(spacep);
1210                                         cm_ReleaseUser(userp);
1211                                         smb_SendTran2Error(vcp, p, opx, code);
1212                                         smb_FreeTran2Packet(outp);
1213                                         return 0;
1214                                 }
1215                         }
1216                 }
1217                 cm_FreeSpace(spacep);
1218         }
1219
1220         /* now do namei and stat, and copy out the info */
1221         code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1222                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1223
1224         if (code) {
1225                 cm_ReleaseUser(userp);
1226                 smb_SendTran2Error(vcp, p, opx, code);
1227                 smb_FreeTran2Packet(outp);
1228                 return 0;
1229         }
1230         
1231         lock_ObtainMutex(&scp->mx);
1232         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1233                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1234         if (code) goto done;
1235         
1236         /* now we have the status in the cache entry, and everything is locked.
1237          * Marshall the output data.
1238          */
1239         op = outp->datap;
1240         /* for info level 108, figure out short name */
1241         if (infoLevel == 0x108) {
1242                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1243                                         tidPathp, scp->fid.vnode, shortName,
1244                                         (size_t *) &len);
1245                 if (code) {
1246                         goto done;
1247                 }
1248
1249                 op = outp->datap;
1250                 *((u_long *)op) = len * 2; op += 4;
1251                 mbstowcs((unsigned short *)op, shortName, len);
1252                 op += (len * 2);
1253
1254                 goto done;
1255         }
1256         if (infoLevel == 1 || infoLevel == 2) {
1257                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1258                 *((u_long *)op) = dosTime; op += 4;     /* creation time */
1259                 *((u_long *)op) = dosTime; op += 4;     /* access time */
1260                 *((u_long *)op) = dosTime; op += 4;     /* write time */
1261                 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1262                 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1263                 attributes = smb_Attributes(scp);
1264                 *((u_short *)op) = attributes; op += 2; /* attributes */
1265         }
1266         else if (infoLevel == 0x101) {
1267                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1268                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1269                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1270                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1271                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1272                 extAttributes = smb_ExtAttributes(scp);
1273                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1274                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1275         }
1276         else if (infoLevel == 0x102) {
1277                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1278                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1279                 *((u_long *)op) = scp->linkCount; op += 4;
1280                 *op++ = 0;
1281                 *op++ = 0;
1282                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1283                 *op++ = 0;
1284         }
1285         else if (infoLevel == 0x103) {
1286                 memset(op, 0, 4); op += 4;      /* EA size */
1287         }
1288
1289         /* now, if we are being asked about extended attrs, return a 0 size */
1290         if (infoLevel == 2) {
1291                 *((u_long *)op) = 0; op += 4;
1292         }
1293         
1294
1295         /* send and free the packets */
1296 done:
1297         lock_ReleaseMutex(&scp->mx);
1298         cm_ReleaseSCache(scp);
1299         cm_ReleaseUser(userp);
1300         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1301         else smb_SendTran2Error(vcp, p, opx, code);
1302         smb_FreeTran2Packet(outp);
1303
1304         return 0;
1305 }
1306
1307 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1308 {
1309         return CM_ERROR_BADOP;
1310 }
1311
1312 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1313 {
1314         smb_tran2Packet_t *outp;
1315         FILETIME ft;
1316         unsigned long attributes;
1317         unsigned short infoLevel;
1318         int nbytesRequired;
1319         unsigned short fid;
1320         cm_user_t *userp;
1321         smb_fid_t *fidp;
1322         cm_scache_t *scp;
1323         char *op;
1324         long code;
1325         cm_req_t req;
1326
1327         cm_InitReq(&req);
1328
1329         fid = p->parmsp[0];
1330         fidp = smb_FindFID(vcp, fid, 0);
1331
1332         if (fidp == NULL) {
1333                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1334                 return 0;
1335         }
1336
1337         infoLevel = p->parmsp[1];
1338         if (infoLevel == 0x101) nbytesRequired = 40;
1339         else if (infoLevel == 0x102) nbytesRequired = 24;
1340         else if (infoLevel == 0x103) nbytesRequired = 4;
1341         else if (infoLevel == 0x104) nbytesRequired = 6;
1342         else {
1343                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1344                          p->opcode, infoLevel);
1345                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1346                 return 0;
1347         }
1348         osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1349
1350         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1351
1352         if (infoLevel > 0x100)
1353                 outp->totalParms = 2;
1354         else
1355                 outp->totalParms = 0;
1356         outp->totalData = nbytesRequired;
1357
1358         userp = smb_GetTran2User(vcp, p);
1359
1360         scp = fidp->scp;
1361         lock_ObtainMutex(&scp->mx);
1362         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1363                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1364         if (code) goto done;
1365
1366         /* now we have the status in the cache entry, and everything is locked.
1367          * Marshall the output data.
1368          */
1369         op = outp->datap;
1370         if (infoLevel == 0x101) {
1371                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1372                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1373                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1374                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1375                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1376                 attributes = smb_ExtAttributes(scp);
1377                 *((u_long *)op) = attributes; op += 4;
1378                 *((u_long *)op) = 0; op += 4;
1379         }
1380         else if (infoLevel == 0x102) {
1381                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1382                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1383                 *((u_long *)op) = scp->linkCount; op += 4;
1384                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1385                 *op++ = 0;
1386                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1387                 *op++ = 0;
1388         }
1389         else if (infoLevel == 0x103) {
1390                 *((u_long *)op) = 0; op += 4;
1391         }
1392         else if (infoLevel == 0x104) {
1393                 unsigned long len;
1394                 char *name;
1395
1396                 if (fidp->NTopen_wholepathp)
1397                         name = fidp->NTopen_wholepathp;
1398                 else
1399                         name = "\\";    /* probably can't happen */
1400                 len = strlen(name);
1401                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1402                 *((u_long *)op) = len * 2; op += 4;
1403                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1404         }
1405
1406         /* send and free the packets */
1407 done:
1408         lock_ReleaseMutex(&scp->mx);
1409         cm_ReleaseUser(userp);
1410         smb_ReleaseFID(fidp);
1411         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1412         else smb_SendTran2Error(vcp, p, opx, code);
1413         smb_FreeTran2Packet(outp);
1414
1415         return 0;
1416 }
1417
1418 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1419 {
1420         long code;
1421         unsigned short fid;
1422         smb_fid_t *fidp;
1423         unsigned short infoLevel;
1424         smb_tran2Packet_t *outp;
1425         cm_user_t *userp;
1426         cm_scache_t *scp;
1427         cm_req_t req;
1428
1429         cm_InitReq(&req);
1430
1431         fid = p->parmsp[0];
1432         fidp = smb_FindFID(vcp, fid, 0);
1433
1434         if (fidp == NULL) {
1435                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1436                 return 0;
1437         }
1438
1439         infoLevel = p->parmsp[1];
1440         if (infoLevel > 0x104 || infoLevel < 0x101) {
1441                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1442                          p->opcode, infoLevel);
1443                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1444                 return 0;
1445         }
1446
1447         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1448                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1449                 return 0;
1450         }
1451         if ((infoLevel == 0x103 || infoLevel == 0x104)
1452             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1453                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1454                 return 0;
1455         }
1456
1457         osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1458
1459         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1460
1461         outp->totalParms = 2;
1462         outp->totalData = 0;
1463
1464         userp = smb_GetTran2User(vcp, p);
1465
1466         scp = fidp->scp;
1467
1468         if (infoLevel == 0x101) {
1469                 FILETIME lastMod;
1470                 unsigned int attribute;
1471                 cm_attr_t attr;
1472
1473                 /* lock the vnode with a callback; we need the current status
1474                  * to determine what the new status is, in some cases.
1475                  */
1476                 lock_ObtainMutex(&scp->mx);
1477                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1478                                  CM_SCACHESYNC_GETSTATUS
1479                                  | CM_SCACHESYNC_NEEDCALLBACK);
1480                 if (code) {
1481                         lock_ReleaseMutex(&scp->mx);
1482                         goto done;
1483                 }
1484
1485                 /* prepare for setattr call */
1486                 attr.mask = 0;
1487                 lastMod = *((FILETIME *)(p->datap + 16));
1488                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1489                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1490                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1491                                                         &lastMod);
1492                         fidp->flags |= SMB_FID_MTIMESETDONE;
1493                 }
1494                 attribute = *((u_long *)(p->datap + 32));
1495                 if (attribute != 0) {
1496                         if ((scp->unixModeBits & 0222)
1497                             && (attribute & 1) != 0) {
1498                                 /* make a writable file read-only */
1499                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1500                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1501                         }
1502                         else if ((scp->unixModeBits & 0222) == 0
1503                                  && (attribute & 1) == 0) {
1504                                 /* make a read-only file writable */
1505                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1506                                 attr.unixModeBits = scp->unixModeBits | 0222;
1507                         }
1508                 }
1509                 lock_ReleaseMutex(&scp->mx);
1510
1511                 /* call setattr */
1512                 if (attr.mask)
1513                         code = cm_SetAttr(scp, &attr, userp, &req);
1514                 else
1515                         code = 0;
1516         }
1517         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1518                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1519                 cm_attr_t attr;
1520
1521                 attr.mask = CM_ATTRMASK_LENGTH;
1522                 attr.length.LowPart = size.LowPart;
1523                 attr.length.HighPart = size.HighPart;
1524                 code = cm_SetAttr(scp, &attr, userp, &req);
1525         }
1526         else if (infoLevel == 0x102) {
1527                 if (*((char *)(p->datap))) {
1528                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1529                                                 &req);
1530                         if (code == 0)
1531                                 fidp->flags |= SMB_FID_DELONCLOSE;
1532                 }
1533                 else {
1534                         code = 0;
1535                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1536                 }
1537         }
1538 done:
1539         cm_ReleaseUser(userp);
1540         smb_ReleaseFID(fidp);
1541         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1542         else smb_SendTran2Error(vcp, p, op, code);
1543         smb_FreeTran2Packet(outp);
1544
1545         return 0;
1546 }
1547
1548 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1549 {
1550         return CM_ERROR_BADOP;
1551 }
1552
1553 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1554 {
1555         return CM_ERROR_BADOP;
1556 }
1557
1558 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1559 {
1560         return CM_ERROR_BADOP;
1561 }
1562
1563 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1564 {
1565         return CM_ERROR_BADOP;
1566 }
1567
1568 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1569 {
1570         return CM_ERROR_BADOP;
1571 }
1572
1573 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1574         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1575         cm_req_t *reqp)
1576 {
1577         long code;
1578         cm_scache_t *scp;
1579         cm_scache_t *targetScp;                 /* target if scp is a symlink */
1580         char *dptr;
1581         long dosTime;
1582         FILETIME ft;
1583         int shortTemp;
1584         unsigned short attr;
1585         unsigned long lattr;
1586         smb_dirListPatch_t *patchp;
1587         smb_dirListPatch_t *npatchp;
1588         
1589         for(patchp = *dirPatchespp; patchp; patchp =
1590                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1591                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1592                 if (code) continue;
1593                 lock_ObtainMutex(&scp->mx);
1594                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1595                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1596                 if (code) {
1597                         lock_ReleaseMutex(&scp->mx);
1598                         cm_ReleaseSCache(scp);
1599                         continue;
1600                 }
1601                 
1602                 /* now watch for a symlink */
1603                 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1604                         lock_ReleaseMutex(&scp->mx);
1605                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1606                                                   reqp);
1607                         if (code == 0) {
1608                                 /* we have a more accurate file to use (the
1609                                  * target of the symbolic link).  Otherwise,
1610                                  * we'll just use the symlink anyway.
1611                                  */
1612                                 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1613                                          scp, targetScp);
1614                                 cm_ReleaseSCache(scp);
1615                                 scp = targetScp;
1616                         }
1617                         lock_ObtainMutex(&scp->mx);
1618                 }
1619
1620                 dptr = patchp->dptr;
1621
1622                 if (infoLevel >= 0x101) {
1623                         /* get filetime */
1624                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1625
1626                         /* copy to Creation Time */
1627                         *((FILETIME *)dptr) = ft;
1628                         dptr += 8;
1629
1630                         /* copy to Last Access Time */
1631                         *((FILETIME *)dptr) = ft;
1632                         dptr += 8;
1633
1634                         /* copy to Last Write Time */
1635                         *((FILETIME *)dptr) = ft;
1636                         dptr += 8;
1637
1638                         /* copy to Change Time */
1639                         *((FILETIME *)dptr) = ft;
1640                         dptr += 8;
1641
1642                         /* Use length for both file length and alloc length */
1643                         *((LARGE_INTEGER *)dptr) = scp->length;
1644                         dptr += 8;
1645                         *((LARGE_INTEGER *)dptr) = scp->length;
1646                         dptr += 8;
1647
1648                         /* Copy attributes */
1649                         lattr = smb_ExtAttributes(scp);
1650                         *((u_long *)dptr) = lattr;
1651                         dptr += 4;
1652                 }
1653                 else {
1654                         /* get dos time */
1655                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1656
1657                         /* and copy out date */
1658                         shortTemp = (dosTime>>16) & 0xffff;
1659                         *((u_short *)dptr) = shortTemp;
1660                         dptr += 2;
1661
1662                         /* copy out creation time */
1663                         shortTemp = dosTime & 0xffff;
1664                         *((u_short *)dptr) = shortTemp;
1665                         dptr += 2;
1666
1667                         /* and copy out date */
1668                         shortTemp = (dosTime>>16) & 0xffff;
1669                         *((u_short *)dptr) = shortTemp;
1670                         dptr += 2;
1671                         
1672                         /* copy out access time */
1673                         shortTemp = dosTime & 0xffff;
1674                         *((u_short *)dptr) = shortTemp;
1675                         dptr += 2;
1676
1677                         /* and copy out date */
1678                         shortTemp = (dosTime>>16) & 0xffff;
1679                         *((u_short *)dptr) = shortTemp;
1680                         dptr += 2;
1681                         
1682                         /* copy out mod time */
1683                         shortTemp = dosTime & 0xffff;
1684                         *((u_short *)dptr) = shortTemp;
1685                         dptr += 2;
1686
1687                         /* copy out file length and alloc length,
1688                          * using the same for both
1689                          */
1690                         *((u_long *)dptr) = scp->length.LowPart;
1691                         dptr += 4;
1692                         *((u_long *)dptr) = scp->length.LowPart;
1693                         dptr += 4;
1694
1695                         /* finally copy out attributes as short */
1696                         attr = smb_Attributes(scp);
1697                         *dptr++ = attr & 0xff;
1698                         *dptr++ = (attr >> 8) & 0xff;
1699                 }
1700
1701                 lock_ReleaseMutex(&scp->mx);
1702                 cm_ReleaseSCache(scp);
1703         }
1704         
1705         /* now free the patches */
1706         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1707                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1708                 free(patchp);
1709         }
1710         
1711         /* and mark the list as empty */
1712         *dirPatchespp = NULL;
1713
1714         return code;
1715 }
1716
1717 /* do a case-folding search of the star name mask with the name in namep.
1718  * Return 1 if we match, otherwise 0.
1719  */
1720 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1721 {
1722         unsigned char tcp1, tcp2;       /* Pattern characters */
1723         unsigned char tcn1;             /* Name characters */
1724         int sawDot = 0, sawStar = 0;
1725         char *starNamep, *starMaskp;
1726         static char nullCharp[] = {0};
1727
1728         /* make sure we only match 8.3 names, if requested */
1729         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1730
1731         /* loop */
1732         while (1) {
1733                 /* Next pattern character */
1734                 tcp1 = *maskp++;
1735
1736                 /* Next name character */
1737                 tcn1 = *namep;
1738
1739                 if (tcp1 == 0) {
1740                         /* 0 - end of pattern */
1741                         if (tcn1 == 0)
1742                                 return 1;
1743                         else
1744                                 return 0;
1745                 }
1746                 else if (tcp1 == '.' || tcp1 == '"') {
1747                         if (sawDot) {
1748                                 if (tcn1 == '.') {
1749                                         namep++;
1750                                         continue;
1751                                 } else
1752                                         return 0;
1753                         }
1754                         else {
1755                                 /*
1756                                  * first dot in pattern;
1757                                  * must match dot or end of name
1758                                  */
1759                                 sawDot = 1;
1760                                 if (tcn1 == 0)
1761                                         continue;
1762                                 else if (tcn1 == '.') {
1763                                         sawStar = 0;
1764                                         namep++;
1765                                         continue;
1766                                 }
1767                                 else
1768                                         return 0;
1769                         }
1770                 }
1771                 else if (tcp1 == '?') {
1772                         if (tcn1 == 0 || tcn1 == '.')
1773                                 return 0;
1774                         namep++;
1775                         continue;
1776                 }
1777                 else if (tcp1 == '>') {
1778                         if (tcn1 != 0 && tcn1 != '.')
1779                                 namep++;
1780                         continue;
1781                 }
1782                 else if (tcp1 == '*' || tcp1 == '<') {
1783                         tcp2 = *maskp++;
1784                         if (tcp2 == 0)
1785                                 return 1;
1786                         else if (tcp2 == '.' || tcp2 == '"') {
1787                                 while (tcn1 != '.' && tcn1 != 0)
1788                                         tcn1 = *++namep;
1789                                 if (tcn1 == 0) {
1790                                         if (sawDot)
1791                                                 return 0;
1792                                         else
1793                                                 continue;
1794                                 }
1795                                 else {
1796                                         namep++;
1797                                         continue;
1798                                 }
1799                         }
1800                         else {
1801                                 /*
1802                                  * pattern character after '*' is not null or
1803                                  * period.  If it is '?' or '>', we are not
1804                                  * going to understand it.  If it is '*' or
1805                                  * '<', we are going to skip over it.  None of
1806                                  * these are likely, I hope.
1807                                  */
1808                                 /* skip over '*' and '<' */
1809                                 while (tcp2 == '*' || tcp2 == '<')
1810                                         tcp2 = *maskp++;
1811
1812                                 /* skip over characters that don't match tcp2 */
1813                                 while (tcn1 != '.' && tcn1 != 0
1814                                         && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1815                                         tcn1 = *++namep;
1816
1817                                 /* No match */
1818                                 if (tcn1 == '.' || tcn1 == 0)
1819                                         return 0;
1820
1821                                 /* Remember where we are */
1822                                 sawStar = 1;
1823                                 starMaskp = maskp;
1824                                 starNamep = namep;
1825
1826                                 namep++;
1827                                 continue;
1828                         }
1829                 }
1830                 else {
1831                         /* tcp1 is not a wildcard */
1832                         if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1833                                 /* they match */
1834                                 namep++;
1835                                 continue;
1836                         }
1837                         /* if trying to match a star pattern, go back */
1838                         if (sawStar) {
1839                                 maskp = starMaskp - 2;
1840                                 namep = starNamep + 1;
1841                                 sawStar = 0;
1842                                 continue;
1843                         }
1844                         /* that's all */
1845                         return 0;
1846                 }
1847         }
1848 }
1849
1850 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1851 {
1852         int attribute;
1853         long nextCookie;
1854         char *tp;
1855         long code;
1856         char *pathp;
1857         cm_dirEntry_t *dep;
1858         int maxCount;
1859         smb_dirListPatch_t *dirListPatchesp;
1860         smb_dirListPatch_t *curPatchp;
1861         cm_buf_t *bufferp;
1862         long temp;
1863         long orbytes;                   /* # of bytes in this output record */
1864         long ohbytes;                   /* # of bytes, except file name */
1865         long onbytes;                   /* # of bytes in name, incl. term. null */
1866         osi_hyper_t dirLength;
1867         osi_hyper_t bufferOffset;
1868         osi_hyper_t curOffset;
1869         osi_hyper_t thyper;
1870         smb_dirSearch_t *dsp;
1871         cm_scache_t *scp;
1872         long entryInDir;
1873         long entryInBuffer;
1874         cm_pageHeader_t *pageHeaderp;
1875         cm_user_t *userp = NULL;
1876         int slotInPage;
1877         int returnedNames;
1878         long nextEntryCookie;
1879         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
1880         char *op;                       /* output data ptr */
1881         char *origOp;                   /* original value of op */
1882         cm_space_t *spacep;             /* for pathname buffer */
1883         long maxReturnData;             /* max # of return data */
1884         long maxReturnParms;            /* max # of return parms */
1885         long bytesInBuffer;             /* # data bytes in the output buffer */
1886         int starPattern;
1887         char *maskp;                    /* mask part of path */
1888         int infoLevel;
1889         int searchFlags;
1890         int eos;
1891         smb_tran2Packet_t *outp;        /* response packet */
1892         char *tidPathp;
1893         int align;
1894         char shortName[13];             /* 8.3 name if needed */
1895         int NeedShortName;
1896         char *shortNameEnd;
1897         int fileType;
1898         cm_fid_t fid;
1899         
1900         cm_req_t req;
1901
1902         cm_InitReq(&req);
1903
1904         eos = 0;
1905         if (p->opcode == 1) {
1906                 /* find first; obtain basic parameters from request */
1907                 attribute = p->parmsp[0];
1908                 maxCount = p->parmsp[1];
1909                 infoLevel = p->parmsp[3];
1910                 searchFlags = p->parmsp[2];
1911                 dsp = smb_NewDirSearch(1);
1912                 dsp->attribute = attribute;
1913                 pathp = ((char *) p->parmsp) + 12;      /* points to path */
1914                 nextCookie = 0;
1915                 maskp = strrchr(pathp, '\\');
1916                 if (maskp == NULL) maskp = pathp;
1917                 else maskp++;   /* skip over backslash */
1918                 strcpy(dsp->mask, maskp);       /* and save mask */
1919                 /* track if this is likely to match a lot of entries */
1920                 starPattern = smb_V3IsStarMask(maskp);
1921         }
1922         else {
1923                 osi_assert(p->opcode == 2);
1924                 /* find next; obtain basic parameters from request or open dir file */
1925                 dsp = smb_FindDirSearch(p->parmsp[0]);
1926                 if (!dsp) return CM_ERROR_BADFD;
1927                 attribute = dsp->attribute;
1928                 maxCount = p->parmsp[1];
1929                 infoLevel = p->parmsp[2];
1930                 searchFlags = p->parmsp[5];
1931                 pathp = NULL;
1932                 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1933                 maskp = dsp->mask;
1934                 starPattern = 1;        /* assume, since required a Find Next */
1935         }
1936
1937         osi_Log4(afsd_logp,
1938                  "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1939                  attribute, infoLevel, maxCount, searchFlags);
1940
1941         osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1942                  p->opcode, nextCookie);
1943
1944         if (infoLevel >= 0x101)
1945                 searchFlags &= ~4;      /* no resume keys */
1946
1947         dirListPatchesp = NULL;
1948
1949         maxReturnData = p->maxReturnData;
1950         if (p->opcode == 1)     /* find first */
1951                 maxReturnParms = 10;    /* bytes */
1952         else
1953                 maxReturnParms = 8;     /* bytes */
1954
1955 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1956         if (maxReturnData > 6000) maxReturnData = 6000;
1957 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1958
1959         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1960                                           maxReturnData);
1961
1962         osi_Log1(afsd_logp, "T2 receive search dir %s",
1963                         osi_LogSaveString(afsd_logp, pathp));
1964         
1965         /* bail out if request looks bad */
1966         if (p->opcode == 1 && !pathp) {
1967                 return CM_ERROR_BADSMB;
1968         }
1969         
1970         osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1971                 nextCookie, dsp->cookie);
1972
1973         userp = smb_GetTran2User(vcp, p);
1974
1975         /* try to get the vnode for the path name next */
1976         lock_ObtainMutex(&dsp->mx);
1977         if (dsp->scp) {
1978                 scp = dsp->scp;
1979                 cm_HoldSCache(scp);
1980                 code = 0;
1981         }
1982         else {
1983                 spacep = cm_GetSpace();
1984                 smb_StripLastComponent(spacep->data, NULL, pathp);
1985                 lock_ReleaseMutex(&dsp->mx);
1986
1987                 tidPathp = smb_GetTIDPath(vcp, p->tid);
1988                 code = cm_NameI(cm_rootSCachep, spacep->data,
1989                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1990                                 userp, tidPathp, &req, &scp);
1991                 cm_FreeSpace(spacep);
1992
1993                 lock_ObtainMutex(&dsp->mx);
1994                 if (code == 0) {
1995                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1996                         dsp->scp = scp;
1997                         /* we need one hold for the entry we just stored into,
1998                          * and one for our own processing.  When we're done
1999                          * with this function, we'll drop the one for our own
2000                          * processing.  We held it once from the namei call,
2001                          * and so we do another hold now.
2002                          */
2003                         cm_HoldSCache(scp);
2004                         lock_ObtainMutex(&scp->mx);
2005                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2006                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2007                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2008                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2009                         }
2010                         lock_ReleaseMutex(&scp->mx);
2011                 }
2012         }
2013         lock_ReleaseMutex(&dsp->mx);
2014         if (code) {
2015                 cm_ReleaseUser(userp);
2016                 smb_FreeTran2Packet(outp);
2017                 smb_DeleteDirSearch(dsp);
2018                 smb_ReleaseDirSearch(dsp);
2019                 return code;
2020         }
2021
2022         /* get the directory size */
2023         lock_ObtainMutex(&scp->mx);
2024         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2025                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2026         if (code) {
2027                 lock_ReleaseMutex(&scp->mx);
2028                 cm_ReleaseSCache(scp);
2029                 cm_ReleaseUser(userp);
2030                 smb_FreeTran2Packet(outp);
2031                 smb_DeleteDirSearch(dsp);
2032                 smb_ReleaseDirSearch(dsp);
2033                 return code;
2034         }
2035         
2036         dirLength = scp->length;
2037         bufferp = NULL;
2038         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2039         curOffset.HighPart = 0;
2040         curOffset.LowPart = nextCookie;
2041         origOp = outp->datap;
2042
2043         code = 0;
2044         returnedNames = 0;
2045         bytesInBuffer = 0;
2046         while (1) {
2047                 op = origOp;
2048                 if (searchFlags & 4)
2049                         /* skip over resume key */
2050                         op += 4;
2051
2052                 /* make sure that curOffset.LowPart doesn't point to the first
2053                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2054                  * point at the first 13 32-byte chunks in the first dir page,
2055                  * since those are dir and page headers, and don't contain useful
2056                  * information.
2057                  */
2058                 temp = curOffset.LowPart & (2048-1);
2059                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2060                         /* we're in the first page */
2061                         if (temp < 13*32) temp = 13*32;
2062                 }
2063                 else {
2064                         /* we're in a later dir page */
2065                         if (temp < 32) temp = 32;
2066                 }
2067                 
2068                 /* make sure the low order 5 bits are zero */
2069                 temp &= ~(32-1);
2070                 
2071                 /* now put temp bits back ito curOffset.LowPart */
2072                 curOffset.LowPart &= ~(2048-1);
2073                 curOffset.LowPart |= temp;
2074
2075                 /* check if we've returned all the names that will fit in the
2076                  * response packet; we check return count as well as the number
2077                  * of bytes requested.  We check the # of bytes after we find
2078                  * the dir entry, since we'll need to check its size.
2079                  */
2080                 if (returnedNames >= maxCount) break;
2081                 
2082                 /* check if we've passed the dir's EOF */
2083                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2084                         eos = 1;
2085                         break;
2086                 }
2087                 
2088                 /* see if we can use the bufferp we have now; compute in which
2089                  * page the current offset would be, and check whether that's
2090                  * the offset of the buffer we have.  If not, get the buffer.
2091                  */
2092                 thyper.HighPart = curOffset.HighPart;
2093                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2094                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2095                         /* wrong buffer */
2096                         if (bufferp) {
2097                                 buf_Release(bufferp);
2098                                 bufferp = NULL;
2099                         }
2100                         lock_ReleaseMutex(&scp->mx);
2101                         lock_ObtainRead(&scp->bufCreateLock);
2102                         code = buf_Get(scp, &thyper, &bufferp);
2103                         lock_ReleaseRead(&scp->bufCreateLock);
2104
2105                         /* now, if we're doing a star match, do bulk fetching
2106                          * of all of the status info for files in the dir.
2107                          */
2108                         if (starPattern) {
2109                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2110                                                           infoLevel, userp,
2111                                                           &req);
2112                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2113                                     && LargeIntegerGreaterThanOrEqualTo(
2114                                                 thyper, scp->bulkStatProgress)) {
2115                                         /* Don't bulk stat if risking timeout */
2116                                         int now = GetCurrentTime();
2117                                         if (now - req.startTime > 5000) {
2118                                                 scp->bulkStatProgress = thyper;
2119                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2120                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2121                                         } else
2122                                                 cm_TryBulkStat(scp, &thyper,
2123                                                                userp, &req);
2124                                 }
2125                         }
2126
2127                         lock_ObtainMutex(&scp->mx);
2128                         if (code) break;
2129                         bufferOffset = thyper;
2130
2131                         /* now get the data in the cache */
2132                         while (1) {
2133                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2134                                         PRSFS_LOOKUP,
2135                                         CM_SCACHESYNC_NEEDCALLBACK
2136                                         | CM_SCACHESYNC_READ);
2137                                 if (code) break;
2138                                 
2139                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2140                                 
2141                                 /* otherwise, load the buffer and try again */
2142                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2143                                                     &req);
2144                                 if (code) break;
2145                         }
2146                         if (code) {
2147                                 buf_Release(bufferp);
2148                                 bufferp = NULL;
2149                                 break;
2150                         }
2151                 }       /* if (wrong buffer) ... */
2152                 
2153                 /* now we have the buffer containing the entry we're interested
2154                  * in; copy it out if it represents a non-deleted entry.
2155                  */
2156                 entryInDir = curOffset.LowPart & (2048-1);
2157                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2158
2159                 /* page header will help tell us which entries are free.  Page
2160                  * header can change more often than once per buffer, since
2161                  * AFS 3 dir page size may be less than (but not more than)
2162                  * a buffer package buffer.
2163                  */
2164                 /* only look intra-buffer */
2165                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2166                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
2167                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2168
2169                 /* now determine which entry we're looking at in the page.
2170                  * If it is free (there's a free bitmap at the start of the
2171                  * dir), we should skip these 32 bytes.
2172                  */
2173                 slotInPage = (entryInDir & 0x7e0) >> 5;
2174                 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2175                         & (1 << (slotInPage & 0x7)))) {
2176                         /* this entry is free */
2177                         numDirChunks = 1;       /* only skip this guy */
2178                         goto nextEntry;
2179                 }
2180
2181                 tp = bufferp->datap + entryInBuffer;
2182                 dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2183
2184                 /* while we're here, compute the next entry's location, too,
2185                  * since we'll need it when writing out the cookie into the dir
2186                  * listing stream.
2187                  *
2188                  * XXXX Probably should do more sanity checking.
2189                  */
2190                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2191                 
2192                 /* compute offset of cookie representing next entry */
2193                 nextEntryCookie = curOffset.LowPart
2194                                     + (CM_DIR_CHUNKSIZE * numDirChunks);
2195
2196                 /* Need 8.3 name? */
2197                 NeedShortName = 0;
2198                 if (infoLevel == 0x104
2199                     && dep->fid.vnode != 0
2200                     && !cm_Is8Dot3(dep->name)) {
2201                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2202                         NeedShortName = 1;
2203                 }
2204
2205                 if (dep->fid.vnode != 0
2206                     && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2207                         || (NeedShortName
2208                             && smb_V3MatchMask(shortName, maskp,
2209                                                 CM_FLAG_CASEFOLD)))) {
2210
2211                         /* Eliminate entries that don't match requested
2212                            attributes */
2213                         if (!(dsp->attribute & 0x10))  /* no directories */
2214                         {
2215                             /* We have already done the cm_TryBulkStat above */
2216                             fid.cell = scp->fid.cell;
2217                             fid.volume = scp->fid.volume;
2218                             fid.vnode = ntohl(dep->fid.vnode);
2219                             fid.unique = ntohl(dep->fid.unique);
2220                             fileType = cm_FindFileType(&fid);
2221                             /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2222                               "has filetype %d", dep->name,
2223                               fileType);*/
2224                             if (fileType == CM_SCACHETYPE_DIRECTORY)
2225                               goto nextEntry;
2226                         }
2227
2228                         /* finally check if this name will fit */
2229
2230                         /* standard dir entry stuff */
2231                         if (infoLevel < 0x101)
2232                                 ohbytes = 23;   /* pre-NT */
2233                         else if (infoLevel == 0x103)
2234                                 ohbytes = 12;   /* NT names only */
2235                         else
2236                                 ohbytes = 64;   /* NT */
2237
2238                         if (infoLevel == 0x104)
2239                                 ohbytes += 26;  /* Short name & length */
2240
2241                         if (searchFlags & 4) {
2242                                 ohbytes += 4;   /* if resume key required */
2243                         }
2244
2245                         if (infoLevel != 1
2246                             && infoLevel != 0x101
2247                             && infoLevel != 0x103)
2248                                 ohbytes += 4;   /* EASIZE */
2249
2250                         /* add header to name & term. null */
2251                         orbytes = onbytes + ohbytes + 1;
2252
2253                         /* now, we round up the record to a 4 byte alignment,
2254                          * and we make sure that we have enough room here for
2255                          * even the aligned version (so we don't have to worry
2256                          * about an * overflow when we pad things out below).
2257                          * That's the reason for the alignment arithmetic below.
2258                          */
2259                         if (infoLevel >= 0x101)
2260                                 align = (4 - (orbytes & 3)) & 3;
2261                         else
2262                                 align = 0;
2263                         if (orbytes + bytesInBuffer + align > maxReturnData)
2264                                 break;
2265
2266                         /* this is one of the entries to use: it is not deleted
2267                          * and it matches the star pattern we're looking for.
2268                          * Put out the name, preceded by its length.
2269                          */
2270                         /* First zero everything else */
2271                         memset(origOp, 0, ohbytes);
2272
2273                         if (infoLevel <= 0x101)
2274                                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2275                         else if (infoLevel == 0x103)
2276                                 *((u_long *)(op + 8)) = onbytes;
2277                         else
2278                                 *((u_long *)(op + 60)) = onbytes;
2279                         strcpy(origOp+ohbytes, dep->name);
2280
2281                         /* Short name if requested and needed */
2282                         if (infoLevel == 0x104) {
2283                                 if (NeedShortName) {
2284                                         strcpy(op + 70, shortName);
2285                                         *(op + 68) = shortNameEnd - shortName;
2286                                 }
2287                         }
2288
2289                         /* now, adjust the # of entries copied */
2290                         returnedNames++;
2291
2292                         /* NextEntryOffset and FileIndex */
2293                         if (infoLevel >= 101) {
2294                                 int entryOffset = orbytes + align;
2295                                 *((u_long *)op) = entryOffset;
2296                                 *((u_long *)(op+4)) = nextEntryCookie;
2297                         }
2298
2299                         /* now we emit the attribute.  This is tricky, since
2300                          * we need to really stat the file to find out what
2301                          * type of entry we've got.  Right now, we're copying
2302                          * out data from * a buffer, while holding the scp
2303                          * locked, so it isn't really convenient to stat
2304                          * something now.  We'll put in a place holder
2305                          * now, and make a second pass before returning this
2306                          * to get the real attributes.  So, we just skip the
2307                          * data for now, and adjust it later.  We allocate a
2308                          * patch record to make it easy to find this point
2309                          * later.  The replay will happen at a time when it is
2310                          * safe to unlock the directory.
2311                          */
2312                         if (infoLevel != 0x103) {
2313                                 curPatchp = malloc(sizeof(*curPatchp));
2314                                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2315                                          &curPatchp->q);
2316                                 curPatchp->dptr = op;
2317                                 if (infoLevel >= 0x101)
2318                                         curPatchp->dptr += 8;
2319                                 curPatchp->fid.cell = scp->fid.cell;
2320                                 curPatchp->fid.volume = scp->fid.volume;
2321                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2322                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2323                         }
2324
2325                         if (searchFlags & 4)
2326                                 /* put out resume key */
2327                                 *((u_long *)origOp) = nextEntryCookie;
2328
2329                         /* Adjust byte ptr and count */
2330                         origOp += orbytes;      /* skip entire record */
2331                         bytesInBuffer += orbytes;
2332
2333                         /* and pad the record out */
2334                         while (--align >= 0) {
2335                                 *origOp++ = 0;
2336                                 bytesInBuffer++;
2337                         }
2338                         
2339                 }       /* if we're including this name */
2340                 
2341 nextEntry:
2342                 /* and adjust curOffset to be where the new cookie is */
2343                 thyper.HighPart = 0;
2344                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2345                 curOffset = LargeIntegerAdd(thyper, curOffset);
2346         }               /* while copying data for dir listing */
2347
2348         /* release the mutex */
2349         lock_ReleaseMutex(&scp->mx);
2350         if (bufferp) buf_Release(bufferp);
2351
2352         /* apply and free last set of patches; if not doing a star match, this
2353          * will be empty, but better safe (and freeing everything) than sorry.
2354          */
2355         smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2356                                   &req);
2357         
2358         /* now put out the final parameters */
2359         if (returnedNames == 0) eos = 1;
2360         if (p->opcode == 1) {
2361                 /* find first */
2362                 outp->parmsp[0] = (unsigned short) dsp->cookie;
2363                 outp->parmsp[1] = returnedNames;
2364                 outp->parmsp[2] = eos;
2365                 outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2366                 outp->parmsp[4] = 0;    /* don't need last name to continue
2367                                          * search, cookie is enough.  Normally,
2368                                          * this is the offset of the file name
2369                                          * of the last entry returned.
2370                                          */
2371                 outp->totalParms = 10;  /* in bytes */
2372         }
2373         else {
2374                 /* find next */
2375                 outp->parmsp[0] = returnedNames;
2376                 outp->parmsp[1] = eos;
2377                 outp->parmsp[2] = 0;    /* EAS error */
2378                 outp->parmsp[3] = 0;    /* last name, as above */
2379                 outp->totalParms = 8;   /* in bytes */
2380         }
2381
2382         /* return # of bytes in the buffer */
2383         outp->totalData = bytesInBuffer;
2384
2385         osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2386                 returnedNames, code);
2387
2388         /* Return error code if unsuccessful on first request */
2389         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2390                 code = CM_ERROR_NOSUCHFILE;
2391
2392         /* if we're supposed to close the search after this request, or if
2393          * we're supposed to close the search if we're done, and we're done,
2394          * or if something went wrong, close the search.
2395          */
2396         /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2397         if ((searchFlags & 1) || (returnedNames == 0)
2398                 || code != 0) smb_DeleteDirSearch(dsp);
2399         if (code)
2400                 smb_SendTran2Error(vcp, p, opx, code);
2401         else {
2402                 smb_SendTran2Packet(vcp, outp, opx);
2403         }
2404         smb_FreeTran2Packet(outp);
2405         smb_ReleaseDirSearch(dsp);
2406         cm_ReleaseSCache(scp);
2407         cm_ReleaseUser(userp);
2408         return 0;
2409 }
2410
2411 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2412 {
2413         int dirHandle;
2414         smb_dirSearch_t *dsp;
2415
2416         dirHandle = smb_GetSMBParm(inp, 0);
2417         
2418         osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2419
2420         dsp = smb_FindDirSearch(dirHandle);
2421         
2422         if (!dsp)
2423                 return CM_ERROR_BADFD;
2424         
2425         /* otherwise, we have an FD to destroy */
2426         smb_DeleteDirSearch(dsp);
2427         smb_ReleaseDirSearch(dsp);
2428         
2429         /* and return results */
2430         smb_SetSMBDataLength(outp, 0);
2431
2432         return 0;
2433 }
2434
2435 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2436 {
2437         smb_SetSMBDataLength(outp, 0);
2438         return 0;
2439 }
2440
2441 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2442 {
2443         char *pathp;
2444         long code;
2445         cm_space_t *spacep;
2446         int excl;
2447         cm_user_t *userp;
2448         cm_scache_t *dscp;              /* dir we're dealing with */
2449         cm_scache_t *scp;               /* file we're creating */
2450         cm_attr_t setAttr;
2451         int initialModeBits;
2452         smb_fid_t *fidp;
2453         int attributes;
2454         char *lastNamep;
2455         long dosTime;
2456         int openFun;
2457         int trunc;
2458         int openMode;
2459         int extraInfo;
2460         int openAction;
2461         int parmSlot;                   /* which parm we're dealing with */
2462         char *tidPathp;
2463         cm_req_t req;
2464
2465         cm_InitReq(&req);
2466
2467         scp = NULL;
2468         
2469         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2470         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2471         excl = ((openFun & 3) == 0);
2472         trunc = ((openFun & 3) == 2);           /* truncate it */
2473         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2474         openAction = 0;                 /* tracks what we did */
2475
2476         attributes = smb_GetSMBParm(inp, 5);
2477         dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2478         
2479         /* compute initial mode bits based on read-only flag in attributes */
2480         initialModeBits = 0666;
2481         if (attributes & 1) initialModeBits &= ~0222;
2482         
2483         pathp = smb_GetSMBData(inp, NULL);
2484
2485         spacep = inp->spacep;
2486         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2487
2488         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2489                 /* special case magic file name for receiving IOCTL requests
2490                  * (since IOCTL calls themselves aren't getting through).
2491                  */
2492                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2493                 smb_SetupIoctlFid(fidp, spacep);
2494
2495                 /* set inp->fid so that later read calls in same msg can find fid */
2496                 inp->fid = fidp->fid;
2497         
2498                 /* copy out remainder of the parms */
2499                 parmSlot = 2;
2500                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2501                 if (extraInfo) {
2502                         smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2503                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* mod time */
2504                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2505                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* len */
2506                         smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2507                         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2508                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2509                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2510                 }
2511                 /* and the final "always present" stuff */
2512                 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2513                 /* next write out the "unique" ID */
2514                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2515                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2516                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2517                 smb_SetSMBDataLength(outp, 0);
2518
2519                 /* and clean up fid reference */
2520                 smb_ReleaseFID(fidp);
2521                 return 0;
2522         }
2523
2524         userp = smb_GetUser(vcp, inp);
2525
2526         dscp = NULL;
2527         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2528         code = cm_NameI(cm_rootSCachep, pathp,
2529                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2530                 userp, tidPathp, &req, &scp);
2531         if (code != 0) {
2532                 code = cm_NameI(cm_rootSCachep, spacep->data,
2533                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2534                                 userp, tidPathp, &req, &dscp);
2535
2536                 if (code) {
2537                         cm_ReleaseUser(userp);
2538                         return code;
2539                 }
2540         
2541                 /* otherwise, scp points to the parent directory.  Do a lookup,
2542                  * and truncate the file if we find it, otherwise we create the
2543                  * file.
2544                  */
2545                 if (!lastNamep) lastNamep = pathp;
2546                 else lastNamep++;
2547                 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2548                                  &req, &scp);
2549                 if (code && code != CM_ERROR_NOSUCHFILE) {
2550                         cm_ReleaseSCache(dscp);
2551                         cm_ReleaseUser(userp);
2552                         return code;
2553                 }
2554         }
2555         
2556         /* if we get here, if code is 0, the file exists and is represented by
2557          * scp.  Otherwise, we have to create it.  The dir may be represented
2558          * by dscp, or we may have found the file directly.  If code is non-zero,
2559          * scp is NULL.
2560          */
2561         if (code == 0) {
2562                 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2563                 if (code) {
2564                         if (dscp) cm_ReleaseSCache(dscp);
2565                         cm_ReleaseSCache(scp);
2566                         cm_ReleaseUser(userp);
2567                         return code;
2568                 }
2569
2570                 if (excl) {
2571                         /* oops, file shouldn't be there */
2572                         if (dscp) cm_ReleaseSCache(dscp);
2573                         cm_ReleaseSCache(scp);
2574                         cm_ReleaseUser(userp);
2575                         return CM_ERROR_EXISTS;
2576                 }
2577
2578                 if (trunc) {
2579                         setAttr.mask = CM_ATTRMASK_LENGTH;
2580                         setAttr.length.LowPart = 0;
2581                         setAttr.length.HighPart = 0;
2582                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2583                         openAction = 3; /* truncated existing file */
2584                 }
2585                 else openAction = 1;    /* found existing file */
2586         }
2587         else if (!(openFun & 0x10)) {
2588                 /* don't create if not found */
2589                 if (dscp) cm_ReleaseSCache(dscp);
2590                 cm_ReleaseUser(userp);
2591                 return CM_ERROR_NOSUCHFILE;
2592         }
2593         else {
2594                 osi_assert(dscp != NULL);
2595                 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2596                                 osi_LogSaveString(afsd_logp, lastNamep));
2597                 openAction = 2; /* created file */
2598                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2599                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2600                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2601                                  &req);
2602                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2603                         smb_NotifyChange(FILE_ACTION_ADDED,
2604                                          FILE_NOTIFY_CHANGE_FILE_NAME,
2605                                          dscp, lastNamep, NULL, TRUE);
2606                 if (!excl && code == CM_ERROR_EXISTS) {
2607                         /* not an exclusive create, and someone else tried
2608                          * creating it already, then we open it anyway.  We
2609                          * don't bother retrying after this, since if this next
2610                          * fails, that means that the file was deleted after we
2611                          * started this call.
2612                          */
2613                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2614                                          userp, &req, &scp);
2615                         if (code == 0) {
2616                                 if (trunc) {
2617                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2618                                         setAttr.length.LowPart = 0;
2619                                         setAttr.length.HighPart = 0;
2620                                         code = cm_SetAttr(scp, &setAttr, userp,
2621                                                           &req);
2622                                 }
2623                         }       /* lookup succeeded */
2624                 }
2625         }
2626         
2627         /* we don't need this any longer */
2628         if (dscp) cm_ReleaseSCache(dscp);
2629
2630         if (code) {
2631                 /* something went wrong creating or truncating the file */
2632                 if (scp) cm_ReleaseSCache(scp);
2633                 cm_ReleaseUser(userp);
2634                 return code;
2635         }
2636         
2637         /* make sure we're about to open a file */
2638         if (scp->fileType != CM_SCACHETYPE_FILE) {
2639                 cm_ReleaseSCache(scp);
2640                 cm_ReleaseUser(userp);
2641                 return CM_ERROR_ISDIR;
2642         }
2643
2644         /* now all we have to do is open the file itself */
2645         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2646         osi_assert(fidp);
2647         
2648         /* save a pointer to the vnode */
2649         fidp->scp = scp;
2650         
2651         /* compute open mode */
2652         if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2653         if (openMode == 1 || openMode == 2)
2654                 fidp->flags |= SMB_FID_OPENWRITE;
2655
2656         smb_ReleaseFID(fidp);
2657         
2658         cm_Open(scp, 0, userp);
2659
2660         /* set inp->fid so that later read calls in same msg can find fid */
2661         inp->fid = fidp->fid;
2662         
2663         /* copy out remainder of the parms */
2664         parmSlot = 2;
2665         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2666         lock_ObtainMutex(&scp->mx);
2667         if (extraInfo) {
2668                 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2669                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2670                 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2671                 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2672                 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2673                 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2674                 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2675                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2676                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2677         }
2678         /* and the final "always present" stuff */
2679         smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2680         /* next write out the "unique" ID */
2681         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2682         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2683         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2684         lock_ReleaseMutex(&scp->mx);
2685         smb_SetSMBDataLength(outp, 0);
2686
2687         osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2688
2689         cm_ReleaseUser(userp);
2690         /* leave scp held since we put it in fidp->scp */
2691         return 0;
2692 }
2693
2694 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2695 {
2696         cm_req_t req;
2697         cm_user_t *userp;
2698         unsigned short fid;
2699         smb_fid_t *fidp;
2700         cm_scache_t *scp;
2701         unsigned char LockType;
2702         unsigned short NumberOfUnlocks, NumberOfLocks;
2703         unsigned long Timeout;
2704         char *op;
2705         LARGE_INTEGER LOffset, LLength;
2706         smb_waitingLock_t *waitingLock;
2707         void *lockp;
2708         long code;
2709         int i;
2710
2711         cm_InitReq(&req);
2712
2713         fid = smb_GetSMBParm(inp, 2);
2714         fid = smb_ChainFID(fid, inp);
2715
2716         fidp = smb_FindFID(vcp, fid, 0);
2717         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2718                 return CM_ERROR_BADFD;
2719         }
2720         /* set inp->fid so that later read calls in same msg can find fid */
2721         inp->fid = fid;
2722
2723         userp = smb_GetUser(vcp, inp);
2724
2725         scp = fidp->scp;
2726
2727         lock_ObtainMutex(&scp->mx);
2728         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2729                          CM_SCACHESYNC_NEEDCALLBACK
2730                          | CM_SCACHESYNC_GETSTATUS
2731                          | CM_SCACHESYNC_LOCK);
2732         if (code) goto doneSync;
2733
2734         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2735         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2736         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2737         NumberOfLocks = smb_GetSMBParm(inp, 7);
2738
2739         op = smb_GetSMBData(inp, NULL);
2740
2741         for (i=0; i<NumberOfUnlocks; i++) {
2742                 if (LockType & 0x10) {
2743                         /* Large Files */
2744                         LOffset.HighPart = *((LONG *)(op + 4));
2745                         LOffset.LowPart = *((DWORD *)(op + 8));
2746                         LLength.HighPart = *((LONG *)(op + 12));
2747                         LLength.LowPart = *((DWORD *)(op + 16));
2748                         op += 20;
2749                 }
2750                 else {
2751                         /* Not Large Files */
2752                         LOffset.HighPart = 0;
2753                         LOffset.LowPart = *((DWORD *)(op + 2));
2754                         LLength.HighPart = 0;
2755                         LLength.LowPart = *((DWORD *)(op + 6));
2756                         op += 10;
2757                 }
2758                 if (LargeIntegerNotEqualToZero(LOffset))
2759                         continue;
2760                 /* Do not check length -- length check done in cm_Unlock */
2761
2762                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2763                 if (code) goto done;
2764         }
2765
2766         for (i=0; i<NumberOfLocks; i++) {
2767                 if (LockType & 0x10) {
2768                         /* Large Files */
2769                         LOffset.HighPart = *((LONG *)(op + 4));
2770                         LOffset.LowPart = *((DWORD *)(op + 8));
2771                         LLength.HighPart = *((LONG *)(op + 12));
2772                         LLength.LowPart = *((DWORD *)(op + 16));
2773                         op += 20;
2774                 }
2775                 else {
2776                         /* Not Large Files */
2777                         LOffset.HighPart = 0;
2778                         LOffset.LowPart = *((DWORD *)(op + 2));
2779                         LLength.HighPart = 0;
2780                         LLength.LowPart = *((DWORD *)(op + 6));
2781                         op += 10;
2782                 }
2783                 if (LargeIntegerNotEqualToZero(LOffset))
2784                         continue;
2785                 if (LargeIntegerLessThan(LOffset, scp->length))
2786                         continue;
2787
2788                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2789                                 userp, &req, &lockp);
2790                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2791                         /* Put on waiting list */
2792                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2793                         waitingLock->vcp = vcp;
2794                         waitingLock->inp = smb_CopyPacket(inp);
2795                         waitingLock->outp = smb_CopyPacket(outp);
2796                         waitingLock->timeRemaining = Timeout;
2797                         waitingLock->lockp = lockp;
2798                         lock_ObtainWrite(&smb_globalLock);
2799                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2800                                  &waitingLock->q);
2801                         osi_Wakeup((long) &smb_allWaitingLocks);
2802                         lock_ReleaseWrite(&smb_globalLock);
2803                         /* don't send reply immediately */
2804                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2805                 }
2806                 if (code) break;
2807         }
2808
2809         if (code) {
2810                 /* release any locks acquired before the failure */
2811         }
2812         else
2813                 smb_SetSMBDataLength(outp, 0);
2814 done:
2815         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2816 doneSync:
2817         lock_ReleaseMutex(&scp->mx);
2818         cm_ReleaseUser(userp);
2819         smb_ReleaseFID(fidp);
2820
2821         return code;
2822 }
2823
2824 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2825 {
2826         unsigned short fid;
2827         smb_fid_t *fidp;
2828         cm_scache_t *scp;
2829         long code;
2830         long searchTime;
2831         cm_user_t *userp;
2832         cm_req_t req;
2833
2834         cm_InitReq(&req);
2835
2836         fid = smb_GetSMBParm(inp, 0);
2837         fid = smb_ChainFID(fid, inp);
2838         
2839         fidp = smb_FindFID(vcp, fid, 0);
2840         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2841                 return CM_ERROR_BADFD;
2842         }
2843         
2844         userp = smb_GetUser(vcp, inp);
2845         
2846         scp = fidp->scp;
2847         
2848         /* otherwise, stat the file */
2849         lock_ObtainMutex(&scp->mx);
2850         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2851                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2852         if (code) goto done;
2853
2854         /* decode times.  We need a search time, but the response to this
2855          * call provides the date first, not the time, as returned in the
2856          * searchTime variable.  So we take the high-order bits first.
2857          */
2858         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2859         smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);   /* ctime */
2860         smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2861         smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);   /* atime */
2862         smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2863         smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);   /* mtime */
2864         smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2865         
2866         /* now handle file size and allocation size */
2867         smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);          /* file size */
2868         smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2869         smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);          /* alloc size */
2870         smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2871         
2872         /* file attribute */
2873         smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2874         
2875         /* and finalize stuff */
2876         smb_SetSMBDataLength(outp, 0);
2877         code = 0;
2878
2879 done:
2880         lock_ReleaseMutex(&scp->mx);
2881         cm_ReleaseUser(userp);
2882         smb_ReleaseFID(fidp);
2883         return code;
2884 }
2885
2886 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2887 {
2888         unsigned short fid;
2889         smb_fid_t *fidp;
2890         cm_scache_t *scp;
2891         long code;
2892         long searchTime;
2893         long unixTime;
2894         cm_user_t *userp;
2895         cm_attr_t attrs;
2896         cm_req_t req;
2897
2898         cm_InitReq(&req);
2899
2900         fid = smb_GetSMBParm(inp, 0);
2901         fid = smb_ChainFID(fid, inp);
2902         
2903         fidp = smb_FindFID(vcp, fid, 0);
2904         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2905                 return CM_ERROR_BADFD;
2906         }
2907         
2908         userp = smb_GetUser(vcp, inp);
2909         
2910         scp = fidp->scp;
2911         
2912         /* now prepare to call cm_setattr.  This message only sets various times,
2913          * and AFS only implements mtime, and we'll set the mtime if that's
2914          * requested.  The others we'll ignore.
2915          */
2916         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2917         
2918         if (searchTime != 0) {
2919                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2920                 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2921                 attrs.clientModTime = unixTime;
2922                 code = cm_SetAttr(scp, &attrs, userp, &req);
2923         }
2924         else code = 0;
2925
2926         cm_ReleaseUser(userp);
2927         smb_ReleaseFID(fidp);
2928         return code;
2929 }
2930
2931
2932 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2933 {
2934         osi_hyper_t offset;
2935         long count, finalCount;
2936         unsigned short fd;
2937         smb_fid_t *fidp;
2938         long code;
2939         cm_user_t *userp;
2940         char *op;
2941         
2942         fd = smb_GetSMBParm(inp, 2);
2943         count = smb_GetSMBParm(inp, 5);
2944         offset.HighPart = 0;    /* too bad */
2945         offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2946         
2947         osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2948                 fd, offset.LowPart, count);
2949         
2950         fd = smb_ChainFID(fd, inp);
2951         fidp = smb_FindFID(vcp, fd, 0);
2952         if (!fidp) {
2953                 return CM_ERROR_BADFD;
2954         }
2955         /* set inp->fid so that later read calls in same msg can find fid */
2956         inp->fid = fd;
2957
2958         if (fidp->flags & SMB_FID_IOCTL) {
2959                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2960         }
2961         
2962         userp = smb_GetUser(vcp, inp);
2963
2964         /* 0 and 1 are reserved for request chaining, were setup by our caller,
2965          * and will be further filled in after we return.
2966          */
2967         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
2968         smb_SetSMBParm(outp, 3, 0);     /* resvd */
2969         smb_SetSMBParm(outp, 4, 0);     /* resvd */
2970         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2971         /* fill in #6 when we have all the parameters' space reserved */
2972         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
2973         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
2974         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
2975         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
2976         smb_SetSMBParm(outp, 11, 0);    /* reserved */
2977
2978         /* get op ptr after putting in the parms, since otherwise we don't
2979          * know where the data really is.
2980          */
2981         op = smb_GetSMBData(outp, NULL);
2982         
2983         /* now fill in offset from start of SMB header to first data byte (to op) */
2984         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2985
2986         /* set the packet data length the count of the # of bytes */
2987         smb_SetSMBDataLength(outp, count);
2988
2989 #ifndef DJGPP
2990         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2991 #else /* DJGPP */
2992         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2993 #endif /* !DJGPP */
2994
2995         /* fix some things up */
2996         smb_SetSMBParm(outp, 5, finalCount);
2997         smb_SetSMBDataLength(outp, finalCount);
2998
2999         smb_ReleaseFID(fidp);
3000
3001         cm_ReleaseUser(userp);
3002         return code;
3003 }
3004         
3005 /*
3006  * Values for createDisp, copied from NTDDK.H
3007  *
3008  *  FILE_SUPERSEDE      0       (???)
3009  *  FILE_OPEN           1       (open)
3010  *  FILE_CREATE         2       (exclusive)
3011  *  FILE_OPEN_IF        3       (non-exclusive)
3012  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3013  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3014  */
3015
3016 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3017 {
3018         char *pathp, *realPathp;
3019         long code;
3020         cm_space_t *spacep;
3021         cm_user_t *userp;
3022         cm_scache_t *dscp;              /* parent dir */
3023         cm_scache_t *scp;               /* file to create or open */
3024         cm_attr_t setAttr;
3025         char *lastNamep;
3026         unsigned short nameLength;
3027         unsigned int flags;
3028         unsigned int requestOpLock;
3029         unsigned int requestBatchOpLock;
3030         unsigned int mustBeDir;
3031         int realDirFlag;
3032         unsigned int desiredAccess;
3033         unsigned int extAttributes;
3034         unsigned int createDisp;
3035         unsigned int createOptions;
3036         int initialModeBits;
3037         unsigned short baseFid;
3038         smb_fid_t *baseFidp;
3039         smb_fid_t *fidp;
3040         cm_scache_t *baseDirp;
3041         unsigned short openAction;
3042         int parmSlot;
3043         long fidflags;
3044         FILETIME ft;
3045         LARGE_INTEGER sz;
3046         char *tidPathp;
3047         BOOL foundscp;
3048         cm_req_t req;
3049
3050         cm_InitReq(&req);
3051
3052         foundscp = FALSE;
3053         scp = NULL;
3054
3055         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3056         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3057                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3058         requestOpLock = flags & 0x02;
3059         requestBatchOpLock = flags & 0x04;
3060         mustBeDir = flags & 0x08;
3061
3062         /*
3063          * Why all of a sudden 32-bit FID?
3064          * We will reject all bits higher than 16.
3065          */
3066         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3067                 return CM_ERROR_INVAL;
3068         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3069         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3070                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3071         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3072                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3073         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3074                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3075         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3076                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3077
3078         /* mustBeDir is never set; createOptions directory bit seems to be
3079          * more important
3080          */
3081         if (createOptions & 1)
3082                 realDirFlag = 1;
3083         else if (createOptions & 0x40)
3084                 realDirFlag = 0;
3085         else
3086                 realDirFlag = -1;
3087
3088         /*
3089          * compute initial mode bits based on read-only flag in
3090          * extended attributes
3091          */
3092         initialModeBits = 0666;
3093         if (extAttributes & 1) initialModeBits &= ~0222;
3094
3095         pathp = smb_GetSMBData(inp, NULL);
3096         /* Sometimes path is not null-terminated, so we make a copy. */
3097         realPathp = malloc(nameLength+1);
3098         memcpy(realPathp, pathp, nameLength);
3099         realPathp[nameLength] = 0;
3100
3101         spacep = inp->spacep;
3102         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3103
3104         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3105                 /* special case magic file name for receiving IOCTL requests
3106                  * (since IOCTL calls themselves aren't getting through).
3107                  */
3108                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3109                 smb_SetupIoctlFid(fidp, spacep);
3110
3111                 /* set inp->fid so that later read calls in same msg can find fid */
3112                 inp->fid = fidp->fid;
3113
3114                 /* out parms */
3115                 parmSlot = 2;
3116                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3117                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3118                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3119                 /* times */
3120                 memset(&ft, 0, sizeof(ft));
3121                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3122                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3123                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3124                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3125                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3126                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3127                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3128                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3129                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3130                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3131                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3132                 smb_SetSMBDataLength(outp, 0);
3133
3134                 /* clean up fid reference */
3135                 smb_ReleaseFID(fidp);
3136                 free(realPathp);
3137                 return 0;
3138         }
3139
3140         userp = smb_GetUser(vcp, inp);
3141
3142         if (baseFid == 0) {
3143                 baseDirp = cm_rootSCachep;
3144                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3145         }
3146         else {
3147                 baseFidp = smb_FindFID(vcp, baseFid, 0);
3148                 baseDirp = baseFidp->scp;
3149                 tidPathp = NULL;
3150         }
3151
3152         /* compute open mode */
3153         fidflags = 0;
3154         if (desiredAccess & DELETE)
3155                 fidflags |= SMB_FID_OPENDELETE;
3156         if (desiredAccess & AFS_ACCESS_READ)
3157                 fidflags |= SMB_FID_OPENREAD;
3158         if (desiredAccess & AFS_ACCESS_WRITE)
3159                 fidflags |= SMB_FID_OPENWRITE;
3160
3161         dscp = NULL;
3162         code = 0;
3163         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3164                         userp, tidPathp, &req, &scp);
3165         if (code == 0) foundscp = TRUE;
3166         if (code != 0
3167             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3168                 /* look up parent directory */
3169                 code = cm_NameI(baseDirp, spacep->data,
3170                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3171                                 userp, tidPathp, &req, &dscp);
3172
3173                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3174
3175                 if (code) {
3176                         cm_ReleaseUser(userp);
3177                         free(realPathp);
3178                         return code;
3179                 }
3180
3181                 if (!lastNamep) lastNamep = realPathp;
3182                 else lastNamep++;
3183
3184                 if (!smb_IsLegalFilename(lastNamep))
3185                         return CM_ERROR_BADNTFILENAME;
3186
3187                 if (!foundscp) {
3188                         code = cm_Lookup(dscp, lastNamep,
3189                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3190                                          userp, &req, &scp);
3191                         if (code && code != CM_ERROR_NOSUCHFILE) {
3192                                 cm_ReleaseSCache(dscp);
3193                                 cm_ReleaseUser(userp);
3194                                 free(realPathp);
3195                                 return code;
3196                         }
3197                 }
3198         }
3199         else {
3200                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3201         }
3202
3203         /* if we get here, if code is 0, the file exists and is represented by
3204          * scp.  Otherwise, we have to create it.  The dir may be represented
3205          * by dscp, or we may have found the file directly.  If code is non-zero,
3206          * scp is NULL.
3207          */
3208         if (code == 0) {
3209                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3210                                       &req);
3211                 if (code) {
3212                         if (dscp) cm_ReleaseSCache(dscp);
3213                         cm_ReleaseSCache(scp);
3214                         cm_ReleaseUser(userp);
3215                         free(realPathp);
3216                         return code;
3217                 }
3218
3219                 if (createDisp == 2) {
3220                         /* oops, file shouldn't be there */
3221                         if (dscp) cm_ReleaseSCache(dscp);
3222                         cm_ReleaseSCache(scp);
3223                         cm_ReleaseUser(userp);
3224                         free(realPathp);
3225                         return CM_ERROR_EXISTS;
3226                 }
3227
3228                 if (createDisp == 4
3229                     || createDisp == 5) {
3230                         setAttr.mask = CM_ATTRMASK_LENGTH;
3231                         setAttr.length.LowPart = 0;
3232                         setAttr.length.HighPart = 0;
3233                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3234                         openAction = 3; /* truncated existing file */
3235                 }
3236                 else openAction = 1;    /* found existing file */
3237         }
3238         else if (createDisp == 1 || createDisp == 4) {
3239                 /* don't create if not found */
3240                 if (dscp) cm_ReleaseSCache(dscp);
3241                 cm_ReleaseUser(userp);
3242                 free(realPathp);
3243                 return CM_ERROR_NOSUCHFILE;
3244         }
3245         else if (realDirFlag == 0 || realDirFlag == -1) {
3246                 osi_assert(dscp != NULL);
3247                 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3248                                 osi_LogSaveString(afsd_logp, lastNamep));
3249                 openAction = 2;         /* created file */
3250                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3251                 setAttr.clientModTime = time(NULL);
3252                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3253                                  &req);
3254                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3255                         smb_NotifyChange(FILE_ACTION_ADDED,
3256                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3257                                          dscp, lastNamep, NULL, TRUE);
3258                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3259                         /* Not an exclusive create, and someone else tried
3260                          * creating it already, then we open it anyway.  We
3261                          * don't bother retrying after this, since if this next
3262                          * fails, that means that the file was deleted after we
3263                          * started this call.
3264                          */
3265                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3266                                          userp, &req, &scp);
3267                         if (code == 0) {
3268                                 if (createDisp == 5) {
3269                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3270                                         setAttr.length.LowPart = 0;
3271                                         setAttr.length.HighPart = 0;
3272                                         code = cm_SetAttr(scp, &setAttr, userp,
3273                                                           &req);
3274                                 }
3275                         }       /* lookup succeeded */
3276                 }
3277         }
3278         else {
3279                 /* create directory */
3280                 osi_assert(dscp != NULL);
3281                 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3282                                 osi_LogSaveString(afsd_logp, lastNamep));
3283                 openAction = 2;         /* created directory */
3284                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3285                 setAttr.clientModTime = time(NULL);
3286                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3287                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3288                         smb_NotifyChange(FILE_ACTION_ADDED,
3289                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3290                                          dscp, lastNamep, NULL, TRUE);
3291                 if (code == 0
3292                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3293                         /* Not an exclusive create, and someone else tried
3294                          * creating it already, then we open it anyway.  We
3295                          * don't bother retrying after this, since if this next
3296                          * fails, that means that the file was deleted after we
3297                          * started this call.
3298                          */
3299                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3300                                          userp, &req, &scp);
3301                 }
3302         }
3303
3304         if (code) {
3305                 /* something went wrong creating or truncating the file */
3306                 if (scp) cm_ReleaseSCache(scp);
3307                 cm_ReleaseUser(userp);
3308                 free(realPathp);
3309                 return code;
3310         }
3311
3312         /* make sure we have file vs. dir right */
3313         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3314                 cm_ReleaseSCache(scp);
3315                 cm_ReleaseUser(userp);
3316                 free(realPathp);
3317                 return CM_ERROR_ISDIR;
3318         }
3319         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3320                 cm_ReleaseSCache(scp);
3321                 cm_ReleaseUser(userp);
3322                 free(realPathp);
3323                 return CM_ERROR_NOTDIR;
3324         }
3325
3326         /* open the file itself */
3327         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3328         osi_assert(fidp);
3329         /* save a pointer to the vnode */
3330         fidp->scp = scp;
3331
3332         fidp->flags = fidflags;
3333
3334         /* save parent dir and pathname for delete or change notification */
3335         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3336                 fidp->flags |= SMB_FID_NTOPEN;
3337                 fidp->NTopen_dscp = dscp;
3338                 cm_HoldSCache(dscp);
3339                 fidp->NTopen_pathp = strdup(lastNamep);
3340         }
3341         fidp->NTopen_wholepathp = realPathp;
3342
3343         /* we don't need this any longer */
3344         if (dscp) cm_ReleaseSCache(dscp);
3345         cm_Open(scp, 0, userp);
3346
3347         /* set inp->fid so that later read calls in same msg can find fid */
3348         inp->fid = fidp->fid;
3349
3350         /* out parms */
3351         parmSlot = 2;
3352         lock_ObtainMutex(&scp->mx);
3353         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3354         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3355         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3356         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3357         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3358         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3359         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3360         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3361         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3362                                                 parmSlot += 2;
3363         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3364         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3365         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3366         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3367         smb_SetSMBParmByte(outp, parmSlot,
3368                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3369         lock_ReleaseMutex(&scp->mx);
3370         smb_SetSMBDataLength(outp, 0);
3371
3372         osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3373                  osi_LogSaveString(afsd_logp, realPathp));
3374
3375         smb_ReleaseFID(fidp);
3376
3377         cm_ReleaseUser(userp);
3378
3379         /* leave scp held since we put it in fidp->scp */
3380         return 0;
3381 }
3382
3383 /*
3384  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3385  * Instead, ultimately, would like to use a subroutine for common code.
3386  */
3387 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3388 {
3389         char *pathp, *realPathp;
3390         long code;
3391         cm_space_t *spacep;
3392         cm_user_t *userp;
3393         cm_scache_t *dscp;              /* parent dir */
3394         cm_scache_t *scp;               /* file to create or open */
3395         cm_attr_t setAttr;
3396         char *lastNamep;
3397         unsigned long nameLength;
3398         unsigned int flags;
3399         unsigned int requestOpLock;
3400         unsigned int requestBatchOpLock;
3401         unsigned int mustBeDir;
3402         int realDirFlag;
3403         unsigned int desiredAccess;
3404         unsigned int extAttributes;
3405         unsigned int createDisp;
3406         unsigned int createOptions;
3407         int initialModeBits;
3408         unsigned short baseFid;
3409         smb_fid_t *baseFidp;
3410         smb_fid_t *fidp;
3411         cm_scache_t *baseDirp;
3412         unsigned short openAction;
3413         int parmSlot;
3414         long fidflags;
3415         FILETIME ft;
3416         char *tidPathp;
3417         BOOL foundscp;
3418         int parmOffset, dataOffset;
3419         char *parmp;
3420         ULONG *lparmp;
3421         char *outData;
3422         cm_req_t req;
3423
3424         cm_InitReq(&req);
3425
3426         foundscp = FALSE;
3427         scp = NULL;
3428
3429         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3430                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3431         parmp = inp->data + parmOffset;
3432         lparmp = (ULONG *) parmp;
3433
3434         flags = lparmp[0];
3435         requestOpLock = flags & 0x02;
3436         requestBatchOpLock = flags & 0x04;
3437         mustBeDir = flags & 0x08;
3438         /*
3439          * Why all of a sudden 32-bit FID?
3440          * We will reject all bits higher than 16.
3441          */
3442         if (lparmp[1] & 0xFFFF0000)
3443                 return CM_ERROR_INVAL;
3444         baseFid = (unsigned short)lparmp[1];
3445         desiredAccess = lparmp[2];
3446         extAttributes = lparmp[5];
3447         createDisp = lparmp[7];
3448         createOptions = lparmp[8];
3449         nameLength = lparmp[11];
3450
3451         /* mustBeDir is never set; createOptions directory bit seems to be
3452          * more important
3453          */
3454         if (createOptions & 1)
3455                 realDirFlag = 1;
3456         else if (createOptions & 0x40)
3457                 realDirFlag = 0;
3458         else
3459                 realDirFlag = -1;
3460
3461         /*
3462          * compute initial mode bits based on read-only flag in
3463          * extended attributes
3464          */
3465         initialModeBits = 0666;
3466         if (extAttributes & 1) initialModeBits &= ~0222;
3467
3468         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3469         /* Sometimes path is not null-terminated, so we make a copy. */
3470         realPathp = malloc(nameLength+1);
3471         memcpy(realPathp, pathp, nameLength);
3472         realPathp[nameLength] = 0;
3473
3474         spacep = cm_GetSpace();
3475         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3476
3477         /*
3478          * Nothing here to handle SMB_IOCTL_FILENAME.
3479          * Will add it if necessary.
3480          */
3481
3482         userp = smb_GetUser(vcp, inp);
3483
3484         if (baseFid == 0) {
3485                 baseDirp = cm_rootSCachep;
3486                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3487         }
3488         else {
3489                 baseFidp = smb_FindFID(vcp, baseFid, 0);
3490                 baseDirp = baseFidp->scp;
3491                 tidPathp = NULL;
3492         }
3493
3494         /* compute open mode */
3495         fidflags = 0;
3496         if (desiredAccess & DELETE)
3497                 fidflags |= SMB_FID_OPENDELETE;
3498         if (desiredAccess & AFS_ACCESS_READ)
3499                 fidflags |= SMB_FID_OPENREAD;
3500         if (desiredAccess & AFS_ACCESS_WRITE)
3501                 fidflags |= SMB_FID_OPENWRITE;
3502
3503         dscp = NULL;
3504         code = 0;
3505         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3506                         userp, tidPathp, &req, &scp);
3507         if (code == 0) foundscp = TRUE;
3508         if (code != 0
3509             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3510                 /* look up parent directory */
3511                 code = cm_NameI(baseDirp, spacep->data,
3512                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3513                                 userp, tidPathp, &req, &dscp);
3514                 cm_FreeSpace(spacep);
3515
3516                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3517
3518                 if (code) {
3519                         cm_ReleaseUser(userp);
3520                         free(realPathp);
3521                         return code;
3522                 }
3523
3524                 if (!lastNamep) lastNamep = realPathp;
3525                 else lastNamep++;
3526
3527                 if (!smb_IsLegalFilename(lastNamep))
3528                         return CM_ERROR_BADNTFILENAME;
3529
3530                 if (!foundscp) {
3531                         code = cm_Lookup(dscp, lastNamep,
3532                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3533                                          userp, &req, &scp);
3534                         if (code && code != CM_ERROR_NOSUCHFILE) {
3535                                 cm_ReleaseSCache(dscp);
3536                                 cm_ReleaseUser(userp);
3537                                 free(realPathp);
3538                                 return code;
3539                         }
3540                 }
3541         }
3542         else {
3543                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3544                 cm_FreeSpace(spacep);
3545         }
3546
3547         /* if we get here, if code is 0, the file exists and is represented by
3548          * scp.  Otherwise, we have to create it.  The dir may be represented
3549          * by dscp, or we may have found the file directly.  If code is non-zero,
3550          * scp is NULL.
3551          */
3552         if (code == 0) {
3553                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3554                                       &req);
3555                 if (code) {
3556                         if (dscp) cm_ReleaseSCache(dscp);
3557                         cm_ReleaseSCache(scp);
3558                         cm_ReleaseUser(userp);
3559                         free(realPathp);
3560                         return code;
3561                 }
3562
3563                 if (createDisp == 2) {
3564                         /* oops, file shouldn't be there */
3565                         if (dscp) cm_ReleaseSCache(dscp);
3566                         cm_ReleaseSCache(scp);
3567                         cm_ReleaseUser(userp);
3568                         free(realPathp);
3569                         return CM_ERROR_EXISTS;
3570                 }
3571
3572                 if (createDisp == 4
3573                     || createDisp == 5) {
3574                         setAttr.mask = CM_ATTRMASK_LENGTH;
3575                         setAttr.length.LowPart = 0;
3576                         setAttr.length.HighPart = 0;
3577                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3578                         openAction = 3; /* truncated existing file */
3579                 }
3580                 else openAction = 1;    /* found existing file */
3581         }
3582         else if (createDisp == 1 || createDisp == 4) {
3583                 /* don't create if not found */
3584                 if (dscp) cm_ReleaseSCache(dscp);
3585                 cm_ReleaseUser(userp);
3586                 free(realPathp);
3587                 return CM_ERROR_NOSUCHFILE;
3588         }
3589         else if (realDirFlag == 0 || realDirFlag == -1) {
3590                 osi_assert(dscp != NULL);
3591                 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3592                                 osi_LogSaveString(afsd_logp, lastNamep));
3593                 openAction = 2;         /* created file */
3594                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3595                 setAttr.clientModTime = time(NULL);
3596                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3597                                  &req);
3598                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3599                         smb_NotifyChange(FILE_ACTION_ADDED,
3600                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3601                                          dscp, lastNamep, NULL, TRUE);
3602                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3603                         /* Not an exclusive create, and someone else tried
3604                          * creating it already, then we open it anyway.  We
3605                          * don't bother retrying after this, since if this next
3606                          * fails, that means that the file was deleted after we
3607                          * started this call.
3608                          */
3609                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3610                                          userp, &req, &scp);
3611                         if (code == 0) {
3612                                 if (createDisp == 5) {
3613                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3614                                         setAttr.length.LowPart = 0;
3615                                         setAttr.length.HighPart = 0;
3616                                         code = cm_SetAttr(scp, &setAttr, userp,
3617                                                           &req);
3618                                 }
3619                         }       /* lookup succeeded */
3620                 }
3621         }
3622         else {
3623                 /* create directory */
3624                 osi_assert(dscp != NULL);
3625                 osi_Log1(afsd_logp,
3626                                 "smb_ReceiveNTTranCreate creating directory %s",
3627                                 osi_LogSaveString(afsd_logp, lastNamep));
3628                 openAction = 2;         /* created directory */
3629                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3630                 setAttr.clientModTime = time(NULL);
3631                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3632                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3633                         smb_NotifyChange(FILE_ACTION_ADDED,
3634                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3635                                          dscp, lastNamep, NULL, TRUE);
3636                 if (code == 0
3637                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3638                         /* Not an exclusive create, and someone else tried
3639                          * creating it already, then we open it anyway.  We
3640                          * don't bother retrying after this, since if this next
3641                          * fails, that means that the file was deleted after we
3642                          * started this call.
3643                          */
3644                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3645                                          userp, &req, &scp);
3646                 }
3647         }
3648
3649         if (code) {
3650                 /* something went wrong creating or truncating the file */
3651                 if (scp) cm_ReleaseSCache(scp);
3652                 cm_ReleaseUser(userp);
3653                 free(realPathp);
3654                 return code;
3655         }
3656
3657         /* make sure we have file vs. dir right */
3658         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3659                 cm_ReleaseSCache(scp);
3660                 cm_ReleaseUser(userp);
3661                 free(realPathp);
3662                 return CM_ERROR_ISDIR;
3663         }
3664         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3665                 cm_ReleaseSCache(scp);
3666                 cm_ReleaseUser(userp);
3667                 free(realPathp);
3668                 return CM_ERROR_NOTDIR;
3669         }
3670
3671         /* open the file itself */
3672         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3673         osi_assert(fidp);
3674
3675         /* save a pointer to the vnode */
3676         fidp->scp = scp;
3677
3678         fidp->flags = fidflags;
3679
3680         /* save parent dir and pathname for deletion or change notification */
3681         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3682                 fidp->flags |= SMB_FID_NTOPEN;
3683                 fidp->NTopen_dscp = dscp;
3684                 cm_HoldSCache(dscp);
3685                 fidp->NTopen_pathp = strdup(lastNamep);
3686         }
3687         fidp->NTopen_wholepathp = realPathp;
3688
3689         /* we don't need this any longer */
3690         if (dscp) cm_ReleaseSCache(dscp);
3691
3692         cm_Open(scp, 0, userp);
3693
3694         /* set inp->fid so that later read calls in same msg can find fid */
3695         inp->fid = fidp->fid;
3696
3697         /* out parms */
3698         parmOffset = 8*4 + 39;
3699         parmOffset += 1;        /* pad to 4 */
3700         dataOffset = parmOffset + 70;
3701
3702         parmSlot = 1;
3703         outp->oddByte = 1;
3704         /* Total Parameter Count */
3705         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3706         /* Total Data Count */
3707         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3708         /* Parameter Count */
3709         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3710         /* Parameter Offset */
3711         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3712         /* Parameter Displacement */
3713         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3714         /* Data Count */
3715         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3716         /* Data Offset */
3717         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3718         /* Data Displacement */
3719         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3720         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
3721         smb_SetSMBDataLength(outp, 70);
3722
3723         lock_ObtainMutex(&scp->mx);
3724         outData = smb_GetSMBData(outp, NULL);
3725         outData++;                      /* round to get to parmOffset */
3726         *outData = 0; outData++;        /* oplock */
3727         *outData = 0; outData++;        /* reserved */
3728         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3729         *((ULONG *)outData) = openAction; outData += 4;
3730         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
3731         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3732         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
3733         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
3734         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
3735         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
3736         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3737         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3738         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3739         *((USHORT *)outData) = 0; outData += 2; /* filetype */
3740         *((USHORT *)outData) = 0; outData += 2; /* dev state */
3741         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3742                                  outData += 2;  /* is a dir? */
3743         lock_ReleaseMutex(&scp->mx);
3744
3745         osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3746
3747         smb_ReleaseFID(fidp);
3748
3749         cm_ReleaseUser(userp);
3750
3751         /* leave scp held since we put it in fidp->scp */
3752         return 0;
3753 }
3754
3755 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3756         smb_packet_t *outp)
3757 {
3758         smb_packet_t *savedPacketp;
3759         ULONG filter; USHORT fid, watchtree;
3760         smb_fid_t *fidp;
3761         cm_scache_t *scp;
3762         
3763         filter = smb_GetSMBParm(inp, 19)
3764                         | (smb_GetSMBParm(inp, 20) << 16);
3765         fid = smb_GetSMBParm(inp, 21);
3766         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3767
3768         savedPacketp = smb_CopyPacket(inp);
3769         savedPacketp->vcp = vcp;
3770         lock_ObtainMutex(&smb_Dir_Watch_Lock);
3771         savedPacketp->nextp = smb_Directory_Watches;
3772         smb_Directory_Watches = savedPacketp;
3773         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3774
3775         fidp = smb_FindFID(vcp, fid, 0);
3776                 
3777         osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3778                  filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3779
3780         scp = fidp->scp;
3781         lock_ObtainMutex(&scp->mx);
3782         if (watchtree)
3783                 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3784         else
3785                 scp->flags |= CM_SCACHEFLAG_WATCHED;
3786         lock_ReleaseMutex(&scp->mx);
3787         smb_ReleaseFID(fidp);
3788
3789         outp->flags |= SMB_PACKETFLAG_NOSEND;
3790
3791         return 0;
3792 }
3793
3794 unsigned char nullSecurityDesc[36] = {
3795         0x01,                           /* security descriptor revision */
3796         0x00,                           /* reserved, should be zero */
3797         0x00, 0x80,                     /* security descriptor control;
3798                                          * 0x8000 : self-relative format */
3799         0x14, 0x00, 0x00, 0x00,         /* offset of owner SID */
3800         0x1c, 0x00, 0x00, 0x00,         /* offset of group SID */
3801         0x00, 0x00, 0x00, 0x00,         /* offset of DACL would go here */
3802         0x00, 0x00, 0x00, 0x00,         /* offset of SACL would go here */
3803         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804                                         /* "null SID" owner SID */
3805         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3806                                         /* "null SID" group SID */
3807 };
3808
3809 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3810 {
3811         int parmOffset, parmCount, dataOffset, dataCount;
3812         int parmSlot;
3813         int maxData;
3814         char *outData;
3815         char *parmp;
3816         USHORT *sparmp;
3817         ULONG *lparmp;
3818         USHORT fid;
3819         ULONG securityInformation;
3820
3821         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3822                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3823         parmp = inp->data + parmOffset;
3824         sparmp = (USHORT *) parmp;
3825         lparmp = (ULONG *) parmp;
3826
3827         fid = sparmp[0];
3828         securityInformation = lparmp[1];
3829
3830         maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3831                         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3832
3833         if (maxData < 36)
3834                 dataCount = 0;
3835         else
3836                 dataCount = 36;
3837
3838         /* out parms */
3839         parmOffset = 8*4 + 39;
3840         parmOffset += 1;        /* pad to 4 */
3841         parmCount = 4;
3842         dataOffset = parmOffset + parmCount;
3843
3844         parmSlot = 1;
3845         outp->oddByte = 1;
3846         /* Total Parameter Count */
3847         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3848         /* Total Data Count */
3849         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3850         /* Parameter Count */
3851         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3852         /* Parameter Offset */
3853         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3854         /* Parameter Displacement */
3855         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3856         /* Data Count */
3857         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3858         /* Data Offset */
3859         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3860         /* Data Displacement */
3861         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3862         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
3863         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3864
3865         outData = smb_GetSMBData(outp, NULL);
3866         outData++;                      /* round to get to parmOffset */
3867         *((ULONG *)outData) = 36; outData += 4; /* length */
3868
3869         if (maxData >= 36) {
3870                 memcpy(outData, nullSecurityDesc, 36);
3871                 outData += 36;
3872                 return 0;
3873         } else
3874                 return CM_ERROR_BUFFERTOOSMALL;
3875 }
3876
3877 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3878 {
3879         unsigned short function;
3880
3881         function = smb_GetSMBParm(inp, 18);
3882
3883         osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3884
3885         /* We can handle long names */
3886         if (vcp->flags & SMB_VCFLAG_USENT)
3887                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
3888         
3889         switch (function) {
3890
3891                 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3892
3893                 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3894
3895                 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3896
3897                 default: return CM_ERROR_INVAL;
3898         }
3899 }
3900
3901 /*
3902  * smb_NotifyChange -- find relevant change notification messages and
3903  *                     reply to them
3904  *
3905  * If we don't know the file name (i.e. a callback break), filename is
3906  * NULL, and we return a zero-length list.
3907  */
3908 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3909         cm_scache_t *dscp, char *filename, char *otherFilename,
3910         BOOL isDirectParent)
3911 {
3912         smb_packet_t *watch, *lastWatch, *nextWatch;
3913         ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3914         char *outData, *oldOutData;
3915         ULONG filter;
3916         USHORT fid, wtree;
3917         ULONG maxLen;
3918         BOOL twoEntries = FALSE;
3919         ULONG otherNameLen, oldParmCount = 0;
3920         DWORD otherAction;
3921         smb_vc_t *vcp;
3922         smb_fid_t *fidp;
3923
3924         /* Get ready for rename within directory */
3925         if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3926                 twoEntries = TRUE;
3927                 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3928         }
3929
3930         lock_ObtainMutex(&smb_Dir_Watch_Lock);
3931         watch = smb_Directory_Watches;
3932         while (watch) {
3933                 filter = smb_GetSMBParm(watch, 19)
3934                                 | (smb_GetSMBParm(watch, 20) << 16);
3935                 fid = smb_GetSMBParm(watch, 21);
3936                 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3937                 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3938                                 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3939                 vcp = watch->vcp;
3940
3941                 /*
3942                  * Strange hack - bug in NT Client and NT Server that we
3943                  * must emulate?
3944                  */
3945                 if (filter == 3 && wtree)
3946                         filter = 0x17;
3947
3948                 fidp = smb_FindFID(vcp, fid, 0);
3949                 if (fidp->scp != dscp
3950                     || (filter & notifyFilter) == 0
3951                     || (!isDirectParent && !wtree)) {
3952                         smb_ReleaseFID(fidp);
3953                         lastWatch = watch;
3954                         watch = watch->nextp;
3955                         continue;
3956                 }
3957                 smb_ReleaseFID(fidp);
3958
3959                 osi_Log4(afsd_logp,
3960                          "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3961                          fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3962
3963                 nextWatch = watch->nextp;
3964                 if (watch == smb_Directory_Watches)
3965                         smb_Directory_Watches = nextWatch;
3966                 else
3967                         lastWatch->nextp = nextWatch;
3968
3969                 /* Turn off WATCHED flag in dscp */
3970                 lock_ObtainMutex(&dscp->mx);
3971                 if (wtree)
3972                         dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3973                 else
3974                         dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3975                 lock_ReleaseMutex(&dscp->mx);
3976
3977                 /* Convert to response packet */
3978                 ((smb_t *) watch)->reb = 0x80;
3979                 ((smb_t *) watch)->wct = 0;
3980
3981                 /* out parms */
3982                 if (filename == NULL)
3983                         parmCount = 0;
3984                 else {
3985                         nameLen = strlen(filename);
3986                         parmCount = 3*4 + nameLen*2;
3987                         parmCount = (parmCount + 3) & ~3;       /* pad to 4 */
3988                         if (twoEntries) {
3989                                 otherNameLen = strlen(otherFilename);
3990                                 oldParmCount = parmCount;
3991                                 parmCount += 3*4 + otherNameLen*2;
3992                                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3993                         }
3994                         if (maxLen < parmCount)
3995                                 parmCount = 0;  /* not enough room */
3996                 }
3997                 parmOffset = 8*4 + 39;
3998                 parmOffset += 1;                        /* pad to 4 */
3999                 dataOffset = parmOffset + parmCount;
4000
4001                 parmSlot = 1;
4002                 watch->oddByte = 1;
4003                 /* Total Parameter Count */
4004                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4005                 /* Total Data Count */
4006                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4007                 /* Parameter Count */
4008                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4009                 /* Parameter Offset */
4010                 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4011                 /* Parameter Displacement */
4012                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4013                 /* Data Count */
4014                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4015                 /* Data Offset */
4016                 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4017                 /* Data Displacement */
4018                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4019                 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4020                 smb_SetSMBDataLength(watch, parmCount + 1);
4021
4022                 if (parmCount != 0) {
4023                         outData = smb_GetSMBData(watch, NULL);
4024                         outData++;      /* round to get to parmOffset */
4025                         oldOutData = outData;
4026                         *((DWORD *)outData) = oldParmCount; outData += 4;
4027                                         /* Next Entry Offset */
4028                         *((DWORD *)outData) = action; outData += 4;
4029                                         /* Action */
4030                         *((DWORD *)outData) = nameLen*2; outData += 4;
4031                                         /* File Name Length */
4032                         mbstowcs((WCHAR *)outData, filename, nameLen);
4033                                         /* File Name */
4034                         if (twoEntries) {
4035                                 outData = oldOutData + oldParmCount;
4036                                 *((DWORD *)outData) = 0; outData += 4;
4037                                         /* Next Entry Offset */
4038                                 *((DWORD *)outData) = otherAction; outData += 4;
4039                                         /* Action */
4040                                 *((DWORD *)outData) = otherNameLen*2;
4041                                 outData += 4;   /* File Name Length */
4042                                 mbstowcs((WCHAR *)outData, otherFilename,
4043                                          otherNameLen); /* File Name */
4044                         }
4045                 }
4046
4047                 /*
4048                  * If filename is null, we don't know the cause of the
4049                  * change notification.  We return zero data (see above),
4050                  * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4051                  * (= 0x010C).  We set the error code here by hand, without
4052                  * modifying wct and bcc.
4053                  */
4054                 if (filename == NULL) {
4055                         ((smb_t *) watch)->rcls = 0x0C;
4056                         ((smb_t *) watch)->reh = 0x01;
4057                         ((smb_t *) watch)->errLow = 0;
4058                         ((smb_t *) watch)->errHigh = 0;
4059                         /* Set NT Status codes flag */
4060                         ((smb_t *) watch)->flg2 |= 0x4000;
4061                 }
4062
4063                 smb_SendPacket(vcp, watch);
4064                 smb_FreePacket(watch);
4065                 watch = nextWatch;
4066         }
4067         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4068 }
4069
4070 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4071 {
4072         unsigned char *replyWctp;
4073         smb_packet_t *watch, *lastWatch;
4074         USHORT fid, watchtree;
4075         smb_fid_t *fidp;
4076         cm_scache_t *scp;
4077
4078         osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4079
4080         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4081         watch = smb_Directory_Watches;
4082         while (watch) {
4083                 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4084                     && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4085                     && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4086                     && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4087                         if (watch == smb_Directory_Watches)
4088                                 smb_Directory_Watches = watch->nextp;
4089                         else
4090                                 lastWatch->nextp = watch->nextp;
4091                         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4092
4093                         /* Turn off WATCHED flag in scp */
4094                         fid = smb_GetSMBParm(watch, 21);
4095                         watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4096
4097                         fidp = smb_FindFID(vcp, fid, 0);
4098                         
4099                         osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s", 
4100                                 fid, watchtree,
4101                                 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4102
4103                         scp = fidp->scp;
4104                         lock_ObtainMutex(&scp->mx);
4105                         if (watchtree)
4106                                 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4107                         else
4108                                 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4109                         lock_ReleaseMutex(&scp->mx);
4110                         smb_ReleaseFID(fidp);
4111
4112                         /* assume STATUS32; return 0xC0000120 (CANCELED) */
4113                         replyWctp = watch->wctp;
4114                         *replyWctp++ = 0;
4115                         *replyWctp++ = 0;
4116                         *replyWctp++ = 0;
4117                         ((smb_t *)watch)->rcls = 0x20;
4118                         ((smb_t *)watch)->reh = 0x1;
4119                         ((smb_t *)watch)->errLow = 0;
4120                         ((smb_t *)watch)->errHigh = 0xC0;
4121                         ((smb_t *)watch)->flg2 |= 0x4000;
4122                         smb_SendPacket(vcp, watch);
4123                         smb_FreePacket(watch);
4124                         return 0;
4125                 }
4126                 lastWatch = watch;
4127                 watch = watch->nextp;
4128         }
4129         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4130
4131         return 0;
4132 }
4133
4134 void smb3_Init()
4135 {
4136         lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4137 }