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