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