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