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