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