hidedots-fix-20040228
[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                 return 0;
1344         }
1345         osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1346
1347         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1348
1349         if (infoLevel > 0x100)
1350                 outp->totalParms = 2;
1351         else
1352                 outp->totalParms = 0;
1353         outp->totalData = nbytesRequired;
1354
1355         userp = smb_GetTran2User(vcp, p);
1356     if(!userp) {
1357         osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1358         code = CM_ERROR_BADSMB;
1359         goto done;
1360     }
1361
1362         scp = fidp->scp;
1363         lock_ObtainMutex(&scp->mx);
1364         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1365                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1366         if (code) goto done;
1367
1368         /* now we have the status in the cache entry, and everything is locked.
1369          * Marshall the output data.
1370          */
1371         op = outp->datap;
1372         if (infoLevel == 0x101) {
1373                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1374                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1375                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1376                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1377                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1378                 attributes = smb_ExtAttributes(scp);
1379                 *((u_long *)op) = attributes; op += 4;
1380                 *((u_long *)op) = 0; op += 4;
1381         }
1382         else if (infoLevel == 0x102) {
1383                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1384                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1385                 *((u_long *)op) = scp->linkCount; op += 4;
1386                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1387                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1388                 *op++ = 0;
1389                 *op++ = 0;
1390         }
1391         else if (infoLevel == 0x103) {
1392                 *((u_long *)op) = 0; op += 4;
1393         }
1394         else if (infoLevel == 0x104) {
1395                 unsigned long len;
1396                 char *name;
1397
1398                 if (fidp->NTopen_wholepathp)
1399                         name = fidp->NTopen_wholepathp;
1400                 else
1401                         name = "\\";    /* probably can't happen */
1402                 len = strlen(name);
1403                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1404                 *((u_long *)op) = len * 2; op += 4;
1405                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1406         }
1407
1408         /* send and free the packets */
1409 done:
1410         lock_ReleaseMutex(&scp->mx);
1411         cm_ReleaseUser(userp);
1412         smb_ReleaseFID(fidp);
1413         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1414         else smb_SendTran2Error(vcp, p, opx, code);
1415         smb_FreeTran2Packet(outp);
1416
1417         return 0;
1418 }
1419
1420 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1421 {
1422         long code;
1423         unsigned short fid;
1424         smb_fid_t *fidp;
1425         unsigned short infoLevel;
1426         smb_tran2Packet_t *outp;
1427         cm_user_t *userp;
1428         cm_scache_t *scp;
1429         cm_req_t req;
1430
1431         cm_InitReq(&req);
1432
1433         fid = p->parmsp[0];
1434         fidp = smb_FindFID(vcp, fid, 0);
1435
1436         if (fidp == NULL) {
1437                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1438                 return 0;
1439         }
1440
1441         infoLevel = p->parmsp[1];
1442         if (infoLevel > 0x104 || infoLevel < 0x101) {
1443                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1444                          p->opcode, infoLevel);
1445                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1446                 return 0;
1447         }
1448
1449         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1450                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1451                 return 0;
1452         }
1453         if ((infoLevel == 0x103 || infoLevel == 0x104)
1454             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1455                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1456                 return 0;
1457         }
1458
1459         osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1460
1461         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1462
1463         outp->totalParms = 2;
1464         outp->totalData = 0;
1465
1466         userp = smb_GetTran2User(vcp, p);
1467     if(!userp) {
1468         osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1469         code = CM_ERROR_BADSMB;
1470         goto done;
1471     }
1472
1473         scp = fidp->scp;
1474
1475         if (infoLevel == 0x101) {
1476                 FILETIME lastMod;
1477                 unsigned int attribute;
1478                 cm_attr_t attr;
1479
1480                 /* lock the vnode with a callback; we need the current status
1481                  * to determine what the new status is, in some cases.
1482                  */
1483                 lock_ObtainMutex(&scp->mx);
1484                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1485                                  CM_SCACHESYNC_GETSTATUS
1486                                  | CM_SCACHESYNC_NEEDCALLBACK);
1487                 if (code) {
1488                         lock_ReleaseMutex(&scp->mx);
1489                         goto done;
1490                 }
1491
1492                 /* prepare for setattr call */
1493                 attr.mask = 0;
1494                 
1495                 lastMod = *((FILETIME *)(p->datap + 16));
1496                 /* when called as result of move a b, lastMod is (-1, -1). 
1497          * If the check for -1 is not present, timestamp
1498                  * of the resulting file will be 1969 (-1)
1499                  */
1500                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
1501             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1502                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1503                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1504                                                         &lastMod);
1505                         fidp->flags |= SMB_FID_MTIMESETDONE;
1506                 }
1507                 
1508                 attribute = *((u_long *)(p->datap + 32));
1509                 if (attribute != 0) {
1510                         if ((scp->unixModeBits & 0222)
1511                             && (attribute & 1) != 0) {
1512                                 /* make a writable file read-only */
1513                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1514                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1515                         }
1516                         else if ((scp->unixModeBits & 0222) == 0
1517                                  && (attribute & 1) == 0) {
1518                                 /* make a read-only file writable */
1519                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1520                                 attr.unixModeBits = scp->unixModeBits | 0222;
1521                         }
1522                 }
1523                 lock_ReleaseMutex(&scp->mx);
1524
1525                 /* call setattr */
1526                 if (attr.mask)
1527                         code = cm_SetAttr(scp, &attr, userp, &req);
1528                 else
1529                         code = 0;
1530         }
1531         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1532                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1533                 cm_attr_t attr;
1534
1535                 attr.mask = CM_ATTRMASK_LENGTH;
1536                 attr.length.LowPart = size.LowPart;
1537                 attr.length.HighPart = size.HighPart;
1538                 code = cm_SetAttr(scp, &attr, userp, &req);
1539         }
1540         else if (infoLevel == 0x102) {
1541                 if (*((char *)(p->datap))) {
1542                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1543                                                 &req);
1544                         if (code == 0)
1545                                 fidp->flags |= SMB_FID_DELONCLOSE;
1546                 }
1547                 else {
1548                         code = 0;
1549                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1550                 }
1551         }
1552 done:
1553         cm_ReleaseUser(userp);
1554         smb_ReleaseFID(fidp);
1555         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1556         else smb_SendTran2Error(vcp, p, op, code);
1557         smb_FreeTran2Packet(outp);
1558
1559         return 0;
1560 }
1561
1562 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1563 {
1564         return CM_ERROR_BADOP;
1565 }
1566
1567 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1568 {
1569         return CM_ERROR_BADOP;
1570 }
1571
1572 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1573 {
1574         return CM_ERROR_BADOP;
1575 }
1576
1577 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1578 {
1579         return CM_ERROR_BADOP;
1580 }
1581
1582 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1583 {
1584         return CM_ERROR_BADOP;
1585 }
1586
1587 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1588         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1589         cm_req_t *reqp)
1590 {
1591         long code;
1592         cm_scache_t *scp;
1593         cm_scache_t *targetScp;                 /* target if scp is a symlink */
1594         char *dptr;
1595         long dosTime;
1596         FILETIME ft;
1597         int shortTemp;
1598         unsigned short attr;
1599         unsigned long lattr;
1600         smb_dirListPatch_t *patchp;
1601         smb_dirListPatch_t *npatchp;
1602         
1603         for(patchp = *dirPatchespp; patchp; patchp =
1604                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1605                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1606                 if (code) continue;
1607                 lock_ObtainMutex(&scp->mx);
1608                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1609                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1610                 if (code) {
1611                         lock_ReleaseMutex(&scp->mx);
1612                         cm_ReleaseSCache(scp);
1613                         continue;
1614                 }
1615                 
1616                 /* now watch for a symlink */
1617                 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1618                         lock_ReleaseMutex(&scp->mx);
1619                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1620                                                   reqp);
1621                         if (code == 0) {
1622                                 /* we have a more accurate file to use (the
1623                                  * target of the symbolic link).  Otherwise,
1624                                  * we'll just use the symlink anyway.
1625                                  */
1626                                 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1627                                          scp, targetScp);
1628                                 cm_ReleaseSCache(scp);
1629                                 scp = targetScp;
1630                         }
1631                         lock_ObtainMutex(&scp->mx);
1632                 }
1633
1634                 dptr = patchp->dptr;
1635
1636                 if (infoLevel >= 0x101) {
1637                         /* get filetime */
1638                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1639
1640                         /* copy to Creation Time */
1641                         *((FILETIME *)dptr) = ft;
1642                         dptr += 8;
1643
1644                         /* copy to Last Access Time */
1645                         *((FILETIME *)dptr) = ft;
1646                         dptr += 8;
1647
1648                         /* copy to Last Write Time */
1649                         *((FILETIME *)dptr) = ft;
1650                         dptr += 8;
1651
1652                         /* copy to Change Time */
1653                         *((FILETIME *)dptr) = ft;
1654                         dptr += 8;
1655
1656                         /* Use length for both file length and alloc length */
1657                         *((LARGE_INTEGER *)dptr) = scp->length;
1658                         dptr += 8;
1659                         *((LARGE_INTEGER *)dptr) = scp->length;
1660                         dptr += 8;
1661
1662                         /* Copy attributes */
1663                         lattr = smb_ExtAttributes(scp);
1664             /* merge in hidden (dot file) attribute */
1665                         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1666                                 lattr |= SMB_ATTR_HIDDEN;
1667                         *((u_long *)dptr) = lattr;
1668                         dptr += 4;
1669                 }
1670                 else {
1671                         /* get dos time */
1672                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1673
1674                         /* and copy out date */
1675                         shortTemp = (dosTime>>16) & 0xffff;
1676                         *((u_short *)dptr) = shortTemp;
1677                         dptr += 2;
1678
1679                         /* copy out creation time */
1680                         shortTemp = dosTime & 0xffff;
1681                         *((u_short *)dptr) = shortTemp;
1682                         dptr += 2;
1683
1684                         /* and copy out date */
1685                         shortTemp = (dosTime>>16) & 0xffff;
1686                         *((u_short *)dptr) = shortTemp;
1687                         dptr += 2;
1688                         
1689                         /* copy out access time */
1690                         shortTemp = dosTime & 0xffff;
1691                         *((u_short *)dptr) = shortTemp;
1692                         dptr += 2;
1693
1694                         /* and copy out date */
1695                         shortTemp = (dosTime>>16) & 0xffff;
1696                         *((u_short *)dptr) = shortTemp;
1697                         dptr += 2;
1698                         
1699                         /* copy out mod time */
1700                         shortTemp = dosTime & 0xffff;
1701                         *((u_short *)dptr) = shortTemp;
1702                         dptr += 2;
1703
1704                         /* copy out file length and alloc length,
1705                          * using the same for both
1706                          */
1707                         *((u_long *)dptr) = scp->length.LowPart;
1708                         dptr += 4;
1709                         *((u_long *)dptr) = scp->length.LowPart;
1710                         dptr += 4;
1711
1712                         /* finally copy out attributes as short */
1713                         attr = smb_Attributes(scp);
1714             /* merge in hidden (dot file) attribute */
1715             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1716                 attr |= SMB_ATTR_HIDDEN;
1717                         *dptr++ = attr & 0xff;
1718                         *dptr++ = (attr >> 8) & 0xff;
1719                 }
1720
1721                 lock_ReleaseMutex(&scp->mx);
1722                 cm_ReleaseSCache(scp);
1723         }
1724         
1725         /* now free the patches */
1726         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1727                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1728                 free(patchp);
1729         }
1730         
1731         /* and mark the list as empty */
1732         *dirPatchespp = NULL;
1733
1734         return code;
1735 }
1736
1737 /* do a case-folding search of the star name mask with the name in namep.
1738  * Return 1 if we match, otherwise 0.
1739  */
1740 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1741 {
1742         unsigned char tcp1, tcp2;       /* Pattern characters */
1743         unsigned char tcn1;             /* Name characters */
1744         int sawDot = 0, sawStar = 0;
1745         char *starNamep, *starMaskp;
1746         static char nullCharp[] = {0};
1747
1748         /* make sure we only match 8.3 names, if requested */
1749         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1750
1751         /* loop */
1752         while (1) {
1753                 /* Next pattern character */
1754                 tcp1 = *maskp++;
1755
1756                 /* Next name character */
1757                 tcn1 = *namep;
1758
1759                 if (tcp1 == 0) {
1760                         /* 0 - end of pattern */
1761                         if (tcn1 == 0)
1762                                 return 1;
1763                         else
1764                                 return 0;
1765                 }
1766                 else if (tcp1 == '.' || tcp1 == '"') {
1767                         if (sawDot) {
1768                                 if (tcn1 == '.') {
1769                                         namep++;
1770                                         continue;
1771                                 } else
1772                                         return 0;
1773                         }
1774                         else {
1775                                 /*
1776                                  * first dot in pattern;
1777                                  * must match dot or end of name
1778                                  */
1779                                 sawDot = 1;
1780                                 if (tcn1 == 0)
1781                                         continue;
1782                                 else if (tcn1 == '.') {
1783                                         sawStar = 0;
1784                                         namep++;
1785                                         continue;
1786                                 }
1787                                 else
1788                                         return 0;
1789                         }
1790                 }
1791                 else if (tcp1 == '?') {
1792                         if (tcn1 == 0 || tcn1 == '.')
1793                                 return 0;
1794                         namep++;
1795                         continue;
1796                 }
1797                 else if (tcp1 == '>') {
1798                         if (tcn1 != 0 && tcn1 != '.')
1799                                 namep++;
1800                         continue;
1801                 }
1802                 else if (tcp1 == '*' || tcp1 == '<') {
1803                         tcp2 = *maskp++;
1804                         if (tcp2 == 0)
1805                                 return 1;
1806                         else if (tcp2 == '.' || tcp2 == '"') {
1807                                 while (tcn1 != '.' && tcn1 != 0)
1808                                         tcn1 = *++namep;
1809                                 if (tcn1 == 0) {
1810                                         if (sawDot)
1811                                                 return 0;
1812                                         else
1813                                                 continue;
1814                                 }
1815                                 else {
1816                                         namep++;
1817                                         continue;
1818                                 }
1819                         }
1820                         else {
1821                                 /*
1822                                  * pattern character after '*' is not null or
1823                                  * period.  If it is '?' or '>', we are not
1824                                  * going to understand it.  If it is '*' or
1825                                  * '<', we are going to skip over it.  None of
1826                                  * these are likely, I hope.
1827                                  */
1828                                 /* skip over '*' and '<' */
1829                                 while (tcp2 == '*' || tcp2 == '<')
1830                                         tcp2 = *maskp++;
1831
1832                                 /* skip over characters that don't match tcp2 */
1833                                 while (tcn1 != '.' && tcn1 != 0
1834                                         && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1835                                         tcn1 = *++namep;
1836
1837                                 /* No match */
1838                                 if (tcn1 == '.' || tcn1 == 0)
1839                                         return 0;
1840
1841                                 /* Remember where we are */
1842                                 sawStar = 1;
1843                                 starMaskp = maskp;
1844                                 starNamep = namep;
1845
1846                                 namep++;
1847                                 continue;
1848                         }
1849                 }
1850                 else {
1851                         /* tcp1 is not a wildcard */
1852                         if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1853                                 /* they match */
1854                                 namep++;
1855                                 continue;
1856                         }
1857                         /* if trying to match a star pattern, go back */
1858                         if (sawStar) {
1859                                 maskp = starMaskp - 2;
1860                                 namep = starNamep + 1;
1861                                 sawStar = 0;
1862                                 continue;
1863                         }
1864                         /* that's all */
1865                         return 0;
1866                 }
1867         }
1868 }
1869
1870 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1871 {
1872         int attribute;
1873         long nextCookie;
1874         char *tp;
1875         long code;
1876         char *pathp;
1877         cm_dirEntry_t *dep;
1878         int maxCount;
1879         smb_dirListPatch_t *dirListPatchesp;
1880         smb_dirListPatch_t *curPatchp;
1881         cm_buf_t *bufferp;
1882         long temp;
1883         long orbytes;                   /* # of bytes in this output record */
1884         long ohbytes;                   /* # of bytes, except file name */
1885         long onbytes;                   /* # of bytes in name, incl. term. null */
1886         osi_hyper_t dirLength;
1887         osi_hyper_t bufferOffset;
1888         osi_hyper_t curOffset;
1889         osi_hyper_t thyper;
1890         smb_dirSearch_t *dsp;
1891         cm_scache_t *scp;
1892         long entryInDir;
1893         long entryInBuffer;
1894         cm_pageHeader_t *pageHeaderp;
1895         cm_user_t *userp = NULL;
1896         int slotInPage;
1897         int returnedNames;
1898         long nextEntryCookie;
1899         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
1900         char *op;                       /* output data ptr */
1901         char *origOp;                   /* original value of op */
1902         cm_space_t *spacep;             /* for pathname buffer */
1903         long maxReturnData;             /* max # of return data */
1904         long maxReturnParms;            /* max # of return parms */
1905         long bytesInBuffer;             /* # data bytes in the output buffer */
1906         int starPattern;
1907         char *maskp;                    /* mask part of path */
1908         int infoLevel;
1909         int searchFlags;
1910         int eos;
1911         smb_tran2Packet_t *outp;        /* response packet */
1912         char *tidPathp;
1913         int align;
1914         char shortName[13];             /* 8.3 name if needed */
1915         int NeedShortName;
1916         char *shortNameEnd;
1917         int fileType;
1918         cm_fid_t fid;
1919         
1920         cm_req_t req;
1921
1922         cm_InitReq(&req);
1923
1924         eos = 0;
1925         if (p->opcode == 1) {
1926                 /* find first; obtain basic parameters from request */
1927                 attribute = p->parmsp[0];
1928                 maxCount = p->parmsp[1];
1929                 infoLevel = p->parmsp[3];
1930                 searchFlags = p->parmsp[2];
1931                 dsp = smb_NewDirSearch(1);
1932                 dsp->attribute = attribute;
1933                 pathp = ((char *) p->parmsp) + 12;      /* points to path */
1934                 nextCookie = 0;
1935                 maskp = strrchr(pathp, '\\');
1936                 if (maskp == NULL) maskp = pathp;
1937                 else maskp++;   /* skip over backslash */
1938                 strcpy(dsp->mask, maskp);       /* and save mask */
1939                 /* track if this is likely to match a lot of entries */
1940                 starPattern = smb_V3IsStarMask(maskp);
1941         }
1942         else {
1943                 osi_assert(p->opcode == 2);
1944                 /* find next; obtain basic parameters from request or open dir file */
1945                 dsp = smb_FindDirSearch(p->parmsp[0]);
1946                 if (!dsp) return CM_ERROR_BADFD;
1947                 attribute = dsp->attribute;
1948                 maxCount = p->parmsp[1];
1949                 infoLevel = p->parmsp[2];
1950                 searchFlags = p->parmsp[5];
1951                 pathp = NULL;
1952                 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1953                 maskp = dsp->mask;
1954                 starPattern = 1;        /* assume, since required a Find Next */
1955         }
1956
1957         osi_Log4(afsd_logp,
1958                  "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1959                  attribute, infoLevel, maxCount, searchFlags);
1960
1961         osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1962                  p->opcode, nextCookie);
1963
1964         if (infoLevel >= 0x101)
1965                 searchFlags &= ~4;      /* no resume keys */
1966
1967         dirListPatchesp = NULL;
1968
1969         maxReturnData = p->maxReturnData;
1970         if (p->opcode == 1)     /* find first */
1971                 maxReturnParms = 10;    /* bytes */
1972         else
1973                 maxReturnParms = 8;     /* bytes */
1974
1975 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1976         if (maxReturnData > 6000) maxReturnData = 6000;
1977 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1978
1979         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1980                                           maxReturnData);
1981
1982         osi_Log1(afsd_logp, "T2 receive search dir %s",
1983                         osi_LogSaveString(afsd_logp, pathp));
1984         
1985         /* bail out if request looks bad */
1986     if (p->opcode == 1 && !pathp) {
1987         smb_ReleaseDirSearch(dsp);
1988         smb_FreeTran2Packet(outp);
1989         return CM_ERROR_BADSMB;
1990     }
1991         
1992         osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1993                 nextCookie, dsp->cookie);
1994
1995         userp = smb_GetTran2User(vcp, p);
1996     if (!userp) {
1997         osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
1998         smb_ReleaseDirSearch(dsp);
1999         smb_FreeTran2Packet(outp);
2000         return CM_ERROR_BADSMB;
2001     }
2002
2003         /* try to get the vnode for the path name next */
2004         lock_ObtainMutex(&dsp->mx);
2005         if (dsp->scp) {
2006                 scp = dsp->scp;
2007                 cm_HoldSCache(scp);
2008                 code = 0;
2009         }
2010         else {
2011                 spacep = cm_GetSpace();
2012                 smb_StripLastComponent(spacep->data, NULL, pathp);
2013                 lock_ReleaseMutex(&dsp->mx);
2014
2015                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2016                 code = cm_NameI(cm_rootSCachep, spacep->data,
2017                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2018                                 userp, tidPathp, &req, &scp);
2019                 cm_FreeSpace(spacep);
2020
2021                 lock_ObtainMutex(&dsp->mx);
2022                 if (code == 0) {
2023                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2024                         dsp->scp = scp;
2025                         /* we need one hold for the entry we just stored into,
2026                          * and one for our own processing.  When we're done
2027                          * with this function, we'll drop the one for our own
2028                          * processing.  We held it once from the namei call,
2029                          * and so we do another hold now.
2030                          */
2031                         cm_HoldSCache(scp);
2032                         lock_ObtainMutex(&scp->mx);
2033                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2034                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2035                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2036                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2037                         }
2038                         lock_ReleaseMutex(&scp->mx);
2039                 }
2040         }
2041         lock_ReleaseMutex(&dsp->mx);
2042         if (code) {
2043                 cm_ReleaseUser(userp);
2044                 smb_FreeTran2Packet(outp);
2045                 smb_DeleteDirSearch(dsp);
2046                 smb_ReleaseDirSearch(dsp);
2047                 return code;
2048         }
2049
2050         /* get the directory size */
2051         lock_ObtainMutex(&scp->mx);
2052         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2053                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2054         if (code) {
2055                 lock_ReleaseMutex(&scp->mx);
2056                 cm_ReleaseSCache(scp);
2057                 cm_ReleaseUser(userp);
2058                 smb_FreeTran2Packet(outp);
2059                 smb_DeleteDirSearch(dsp);
2060                 smb_ReleaseDirSearch(dsp);
2061                 return code;
2062         }
2063         
2064         dirLength = scp->length;
2065         bufferp = NULL;
2066         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2067         curOffset.HighPart = 0;
2068         curOffset.LowPart = nextCookie;
2069         origOp = outp->datap;
2070
2071         code = 0;
2072         returnedNames = 0;
2073         bytesInBuffer = 0;
2074         while (1) {
2075                 op = origOp;
2076                 if (searchFlags & 4)
2077                         /* skip over resume key */
2078                         op += 4;
2079
2080                 /* make sure that curOffset.LowPart doesn't point to the first
2081                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2082                  * point at the first 13 32-byte chunks in the first dir page,
2083                  * since those are dir and page headers, and don't contain useful
2084                  * information.
2085                  */
2086                 temp = curOffset.LowPart & (2048-1);
2087                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2088                         /* we're in the first page */
2089                         if (temp < 13*32) temp = 13*32;
2090                 }
2091                 else {
2092                         /* we're in a later dir page */
2093                         if (temp < 32) temp = 32;
2094                 }
2095                 
2096                 /* make sure the low order 5 bits are zero */
2097                 temp &= ~(32-1);
2098                 
2099                 /* now put temp bits back ito curOffset.LowPart */
2100                 curOffset.LowPart &= ~(2048-1);
2101                 curOffset.LowPart |= temp;
2102
2103             /* check if we've passed the dir's EOF */
2104             if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2105                 eos = 1;
2106                 break;
2107             }
2108
2109             /* check if we've returned all the names that will fit in the
2110              * response packet; we check return count as well as the number
2111              * of bytes requested.  We check the # of bytes after we find
2112              * the dir entry, since we'll need to check its size.
2113              */
2114             if (returnedNames >= maxCount) {
2115                 break;
2116             }
2117                 
2118             /* see if we can use the bufferp we have now; compute in which
2119              * page the current offset would be, and check whether that's
2120              * the offset of the buffer we have.  If not, get the buffer.
2121              */
2122             thyper.HighPart = curOffset.HighPart;
2123             thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2124             if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2125                         /* wrong buffer */
2126                 if (bufferp) {
2127                     buf_Release(bufferp);
2128                     bufferp = NULL;
2129                         }   
2130                         lock_ReleaseMutex(&scp->mx);
2131                         lock_ObtainRead(&scp->bufCreateLock);
2132                         code = buf_Get(scp, &thyper, &bufferp);
2133                         lock_ReleaseRead(&scp->bufCreateLock);
2134
2135                         /* now, if we're doing a star match, do bulk fetching
2136                          * of all of the status info for files in the dir.
2137                          */
2138                         if (starPattern) {
2139                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2140                                                           infoLevel, userp,
2141                                                           &req);
2142                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2143                                     && LargeIntegerGreaterThanOrEqualTo(
2144                                                 thyper, scp->bulkStatProgress)) {
2145                                         /* Don't bulk stat if risking timeout */
2146                                         int now = GetCurrentTime();
2147                                         if (now - req.startTime > 5000) {
2148                                                 scp->bulkStatProgress = thyper;
2149                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2150                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2151                                         } else
2152                                                 cm_TryBulkStat(scp, &thyper,
2153                                                                userp, &req);
2154                                 }
2155                         }
2156
2157                         lock_ObtainMutex(&scp->mx);
2158                         if (code) break;
2159                         bufferOffset = thyper;
2160
2161                         /* now get the data in the cache */
2162                         while (1) {
2163                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2164                                         PRSFS_LOOKUP,
2165                                         CM_SCACHESYNC_NEEDCALLBACK
2166                                         | CM_SCACHESYNC_READ);
2167                                 if (code) break;
2168                                 
2169                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2170                                 
2171                                 /* otherwise, load the buffer and try again */
2172                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2173                                                     &req);
2174                                 if (code) break;
2175                         }
2176                         if (code) {
2177                                 buf_Release(bufferp);
2178                                 bufferp = NULL;
2179                                 break;
2180                         }
2181                 }       /* if (wrong buffer) ... */
2182                 
2183                 /* now we have the buffer containing the entry we're interested
2184                  * in; copy it out if it represents a non-deleted entry.
2185                  */
2186                 entryInDir = curOffset.LowPart & (2048-1);
2187                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2188
2189                 /* page header will help tell us which entries are free.  Page
2190                  * header can change more often than once per buffer, since
2191                  * AFS 3 dir page size may be less than (but not more than)
2192                  * a buffer package buffer.
2193                  */
2194                 /* only look intra-buffer */
2195                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2196                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
2197                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2198
2199                 /* now determine which entry we're looking at in the page.
2200                  * If it is free (there's a free bitmap at the start of the
2201                  * dir), we should skip these 32 bytes.
2202                  */
2203                 slotInPage = (entryInDir & 0x7e0) >> 5;
2204                 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2205                         & (1 << (slotInPage & 0x7)))) {
2206                         /* this entry is free */
2207                         numDirChunks = 1;       /* only skip this guy */
2208                         goto nextEntry;
2209                 }
2210
2211                 tp = bufferp->datap + entryInBuffer;
2212                 dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2213
2214                 /* while we're here, compute the next entry's location, too,
2215                  * since we'll need it when writing out the cookie into the dir
2216                  * listing stream.
2217                  *
2218                  * XXXX Probably should do more sanity checking.
2219                  */
2220                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2221                 
2222                 /* compute offset of cookie representing next entry */
2223                 nextEntryCookie = curOffset.LowPart
2224                                     + (CM_DIR_CHUNKSIZE * numDirChunks);
2225
2226                 /* Need 8.3 name? */
2227                 NeedShortName = 0;
2228                 if (infoLevel == 0x104
2229                     && dep->fid.vnode != 0
2230                     && !cm_Is8Dot3(dep->name)) {
2231                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2232                         NeedShortName = 1;
2233                 }
2234
2235                 if (dep->fid.vnode != 0
2236                     && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2237                         || (NeedShortName
2238                             && smb_V3MatchMask(shortName, maskp,
2239                                                 CM_FLAG_CASEFOLD)))) {
2240
2241                         /* Eliminate entries that don't match requested
2242                            attributes */
2243                     if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
2244                         smb_IsDotFile(dep->name))
2245                         goto nextEntry; /* no hidden files */
2246                     
2247                     if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
2248                     {
2249                             /* We have already done the cm_TryBulkStat above */
2250                             fid.cell = scp->fid.cell;
2251                             fid.volume = scp->fid.volume;
2252                             fid.vnode = ntohl(dep->fid.vnode);
2253                             fid.unique = ntohl(dep->fid.unique);
2254                             fileType = cm_FindFileType(&fid);
2255                             /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2256                               "has filetype %d", dep->name,
2257                               fileType);*/
2258                             if (fileType == CM_SCACHETYPE_DIRECTORY)
2259                               goto nextEntry;
2260                         }
2261
2262                         /* finally check if this name will fit */
2263
2264                         /* standard dir entry stuff */
2265                         if (infoLevel < 0x101)
2266                                 ohbytes = 23;   /* pre-NT */
2267                         else if (infoLevel == 0x103)
2268                                 ohbytes = 12;   /* NT names only */
2269                         else
2270                                 ohbytes = 64;   /* NT */
2271
2272                         if (infoLevel == 0x104)
2273                                 ohbytes += 26;  /* Short name & length */
2274
2275                         if (searchFlags & 4) {
2276                                 ohbytes += 4;   /* if resume key required */
2277                         }
2278
2279                         if (infoLevel != 1
2280                             && infoLevel != 0x101
2281                             && infoLevel != 0x103)
2282                                 ohbytes += 4;   /* EASIZE */
2283
2284                         /* add header to name & term. null */
2285                         orbytes = onbytes + ohbytes + 1;
2286
2287                         /* now, we round up the record to a 4 byte alignment,
2288                          * and we make sure that we have enough room here for
2289                          * even the aligned version (so we don't have to worry
2290                          * about an * overflow when we pad things out below).
2291                          * That's the reason for the alignment arithmetic below.
2292                          */
2293                         if (infoLevel >= 0x101)
2294                                 align = (4 - (orbytes & 3)) & 3;
2295                         else
2296                                 align = 0;
2297                         if (orbytes + bytesInBuffer + align > maxReturnData)
2298                                 break;
2299
2300                         /* this is one of the entries to use: it is not deleted
2301                          * and it matches the star pattern we're looking for.
2302                          * Put out the name, preceded by its length.
2303                          */
2304                         /* First zero everything else */
2305                         memset(origOp, 0, ohbytes);
2306
2307                         if (infoLevel <= 0x101)
2308                                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2309                         else if (infoLevel == 0x103)
2310                                 *((u_long *)(op + 8)) = onbytes;
2311                         else
2312                                 *((u_long *)(op + 60)) = onbytes;
2313                         strcpy(origOp+ohbytes, dep->name);
2314
2315                         /* Short name if requested and needed */
2316                         if (infoLevel == 0x104) {
2317                                 if (NeedShortName) {
2318                                         strcpy(op + 70, shortName);
2319                                         *(op + 68) = shortNameEnd - shortName;
2320                                 }
2321                         }
2322
2323                         /* now, adjust the # of entries copied */
2324                         returnedNames++;
2325
2326                         /* NextEntryOffset and FileIndex */
2327                         if (infoLevel >= 101) {
2328                                 int entryOffset = orbytes + align;
2329                                 *((u_long *)op) = entryOffset;
2330                                 *((u_long *)(op+4)) = nextEntryCookie;
2331                         }
2332
2333                         /* now we emit the attribute.  This is tricky, since
2334                          * we need to really stat the file to find out what
2335                          * type of entry we've got.  Right now, we're copying
2336                          * out data from * a buffer, while holding the scp
2337                          * locked, so it isn't really convenient to stat
2338                          * something now.  We'll put in a place holder
2339                          * now, and make a second pass before returning this
2340                          * to get the real attributes.  So, we just skip the
2341                          * data for now, and adjust it later.  We allocate a
2342                          * patch record to make it easy to find this point
2343                          * later.  The replay will happen at a time when it is
2344                          * safe to unlock the directory.
2345                          */
2346                         if (infoLevel != 0x103) {
2347                                 curPatchp = malloc(sizeof(*curPatchp));
2348                                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2349                                          &curPatchp->q);
2350                                 curPatchp->dptr = op;
2351                                 if (infoLevel >= 0x101)
2352                                         curPatchp->dptr += 8;
2353
2354                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2355                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2356                 }
2357                 else
2358                     curPatchp->flags = 0;
2359
2360                                 curPatchp->fid.cell = scp->fid.cell;
2361                                 curPatchp->fid.volume = scp->fid.volume;
2362                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2363                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2364
2365                                 /* temp */
2366                                 curPatchp->dep = dep;
2367                         }
2368
2369                         if (searchFlags & 4)
2370                                 /* put out resume key */
2371                                 *((u_long *)origOp) = nextEntryCookie;
2372
2373                         /* Adjust byte ptr and count */
2374                         origOp += orbytes;      /* skip entire record */
2375                         bytesInBuffer += orbytes;
2376
2377                         /* and pad the record out */
2378                         while (--align >= 0) {
2379                                 *origOp++ = 0;
2380                                 bytesInBuffer++;
2381                         }
2382                         
2383                 }       /* if we're including this name */
2384                 
2385 nextEntry:
2386                 /* and adjust curOffset to be where the new cookie is */
2387                 thyper.HighPart = 0;
2388                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2389                 curOffset = LargeIntegerAdd(thyper, curOffset);
2390         }               /* while copying data for dir listing */
2391
2392         /* release the mutex */
2393         lock_ReleaseMutex(&scp->mx);
2394         if (bufferp) buf_Release(bufferp);
2395
2396         /* apply and free last set of patches; if not doing a star match, this
2397          * will be empty, but better safe (and freeing everything) than sorry.
2398          */
2399         smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2400                                   &req);
2401         
2402         /* now put out the final parameters */
2403         if (returnedNames == 0) eos = 1;
2404         if (p->opcode == 1) {
2405                 /* find first */
2406                 outp->parmsp[0] = (unsigned short) dsp->cookie;
2407                 outp->parmsp[1] = returnedNames;
2408                 outp->parmsp[2] = eos;
2409                 outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2410                 outp->parmsp[4] = 0;    /* don't need last name to continue
2411                                          * search, cookie is enough.  Normally,
2412                                          * this is the offset of the file name
2413                                          * of the last entry returned.
2414                                          */
2415                 outp->totalParms = 10;  /* in bytes */
2416         }
2417         else {
2418                 /* find next */
2419                 outp->parmsp[0] = returnedNames;
2420                 outp->parmsp[1] = eos;
2421                 outp->parmsp[2] = 0;    /* EAS error */
2422                 outp->parmsp[3] = 0;    /* last name, as above */
2423                 outp->totalParms = 8;   /* in bytes */
2424         }
2425
2426         /* return # of bytes in the buffer */
2427         outp->totalData = bytesInBuffer;
2428
2429         osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2430                 returnedNames, code);
2431
2432         /* Return error code if unsuccessful on first request */
2433         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2434                 code = CM_ERROR_NOSUCHFILE;
2435
2436         /* if we're supposed to close the search after this request, or if
2437          * we're supposed to close the search if we're done, and we're done,
2438          * or if something went wrong, close the search.
2439          */
2440         /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2441         if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2442                                                           eos) || code != 0)
2443             smb_DeleteDirSearch(dsp);
2444         if (code)
2445                 smb_SendTran2Error(vcp, p, opx, code);
2446         else {
2447                 smb_SendTran2Packet(vcp, outp, opx);
2448         }
2449         smb_FreeTran2Packet(outp);
2450         smb_ReleaseDirSearch(dsp);
2451         cm_ReleaseSCache(scp);
2452         cm_ReleaseUser(userp);
2453         return 0;
2454 }
2455
2456 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2457 {
2458         int dirHandle;
2459         smb_dirSearch_t *dsp;
2460
2461         dirHandle = smb_GetSMBParm(inp, 0);
2462         
2463         osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2464
2465         dsp = smb_FindDirSearch(dirHandle);
2466         
2467         if (!dsp)
2468                 return CM_ERROR_BADFD;
2469         
2470         /* otherwise, we have an FD to destroy */
2471         smb_DeleteDirSearch(dsp);
2472         smb_ReleaseDirSearch(dsp);
2473         
2474         /* and return results */
2475         smb_SetSMBDataLength(outp, 0);
2476
2477         return 0;
2478 }
2479
2480 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2481 {
2482         smb_SetSMBDataLength(outp, 0);
2483         return 0;
2484 }
2485
2486 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2487 {
2488         char *pathp;
2489         long code;
2490         cm_space_t *spacep;
2491         int excl;
2492         cm_user_t *userp;
2493         cm_scache_t *dscp;              /* dir we're dealing with */
2494         cm_scache_t *scp;               /* file we're creating */
2495         cm_attr_t setAttr;
2496         int initialModeBits;
2497         smb_fid_t *fidp;
2498         int attributes;
2499         char *lastNamep;
2500         long dosTime;
2501         int openFun;
2502         int trunc;
2503         int openMode;
2504         int extraInfo;
2505         int openAction;
2506         int parmSlot;                   /* which parm we're dealing with */
2507         char *tidPathp;
2508         cm_req_t req;
2509
2510         cm_InitReq(&req);
2511
2512         scp = NULL;
2513         
2514         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2515         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2516         excl = ((openFun & 3) == 0);
2517         trunc = ((openFun & 3) == 2);           /* truncate it */
2518         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2519         openAction = 0;                 /* tracks what we did */
2520
2521         attributes = smb_GetSMBParm(inp, 5);
2522         dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2523         
2524         /* compute initial mode bits based on read-only flag in attributes */
2525         initialModeBits = 0666;
2526         if (attributes & 1) initialModeBits &= ~0222;
2527         
2528         pathp = smb_GetSMBData(inp, NULL);
2529
2530         spacep = inp->spacep;
2531         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2532
2533         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2534                 /* special case magic file name for receiving IOCTL requests
2535          * (since IOCTL calls themselves aren't getting through).
2536          */
2537 #ifdef NOTSERVICE
2538         osi_Log0(afsd_logp, "IOCTL Open");
2539 #endif
2540
2541                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542                 smb_SetupIoctlFid(fidp, spacep);
2543
2544                 /* set inp->fid so that later read calls in same msg can find fid */
2545                 inp->fid = fidp->fid;
2546         
2547                 /* copy out remainder of the parms */
2548                 parmSlot = 2;
2549                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2550                 if (extraInfo) {
2551                         smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2552                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* mod time */
2553                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2554                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* len */
2555                         smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2556                         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2557                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2558                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2559                 }
2560                 /* and the final "always present" stuff */
2561                 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2562                 /* next write out the "unique" ID */
2563                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2564                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2565                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2566                 smb_SetSMBDataLength(outp, 0);
2567
2568                 /* and clean up fid reference */
2569                 smb_ReleaseFID(fidp);
2570                 return 0;
2571         }
2572
2573 #ifdef DEBUG_VERBOSE
2574     {
2575         char *hexp, *asciip;
2576         asciip = (lastNamep ? lastNamep : pathp );
2577         hexp = osi_HexifyString(asciip);
2578         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2579         free(hexp);
2580     }
2581 #endif
2582     userp = smb_GetUser(vcp, inp);
2583
2584         dscp = NULL;
2585         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2586         code = cm_NameI(cm_rootSCachep, pathp,
2587                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2588                 userp, tidPathp, &req, &scp);
2589         if (code != 0) {
2590                 code = cm_NameI(cm_rootSCachep, spacep->data,
2591                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2592                                 userp, tidPathp, &req, &dscp);
2593
2594                 if (code) {
2595                         cm_ReleaseUser(userp);
2596                         return code;
2597                 }
2598         
2599                 /* otherwise, scp points to the parent directory.  Do a lookup,
2600                  * and truncate the file if we find it, otherwise we create the
2601                  * file.
2602                  */
2603                 if (!lastNamep) lastNamep = pathp;
2604                 else lastNamep++;
2605                 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2606                                  &req, &scp);
2607                 if (code && code != CM_ERROR_NOSUCHFILE) {
2608                         cm_ReleaseSCache(dscp);
2609                         cm_ReleaseUser(userp);
2610                         return code;
2611                 }
2612         }
2613         
2614         /* if we get here, if code is 0, the file exists and is represented by
2615          * scp.  Otherwise, we have to create it.  The dir may be represented
2616          * by dscp, or we may have found the file directly.  If code is non-zero,
2617          * scp is NULL.
2618          */
2619         if (code == 0) {
2620                 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2621                 if (code) {
2622                         if (dscp) cm_ReleaseSCache(dscp);
2623                         cm_ReleaseSCache(scp);
2624                         cm_ReleaseUser(userp);
2625                         return code;
2626                 }
2627
2628                 if (excl) {
2629                         /* oops, file shouldn't be there */
2630                         if (dscp) cm_ReleaseSCache(dscp);
2631                         cm_ReleaseSCache(scp);
2632                         cm_ReleaseUser(userp);
2633                         return CM_ERROR_EXISTS;
2634                 }
2635
2636                 if (trunc) {
2637                         setAttr.mask = CM_ATTRMASK_LENGTH;
2638                         setAttr.length.LowPart = 0;
2639                         setAttr.length.HighPart = 0;
2640                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2641                         openAction = 3; /* truncated existing file */
2642                 }
2643                 else openAction = 1;    /* found existing file */
2644         }
2645         else if (!(openFun & 0x10)) {
2646                 /* don't create if not found */
2647                 if (dscp) cm_ReleaseSCache(dscp);
2648                 cm_ReleaseUser(userp);
2649                 return CM_ERROR_NOSUCHFILE;
2650         }
2651         else {
2652                 osi_assert(dscp != NULL);
2653                 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2654                                 osi_LogSaveString(afsd_logp, lastNamep));
2655                 openAction = 2; /* created file */
2656                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2657                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2658                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2659                                  &req);
2660                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2661                         smb_NotifyChange(FILE_ACTION_ADDED,
2662                                          FILE_NOTIFY_CHANGE_FILE_NAME,
2663                                          dscp, lastNamep, NULL, TRUE);
2664                 if (!excl && code == CM_ERROR_EXISTS) {
2665                         /* not an exclusive create, and someone else tried
2666                          * creating it already, then we open it anyway.  We
2667                          * don't bother retrying after this, since if this next
2668                          * fails, that means that the file was deleted after we
2669                          * started this call.
2670                          */
2671                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2672                                          userp, &req, &scp);
2673                         if (code == 0) {
2674                                 if (trunc) {
2675                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2676                                         setAttr.length.LowPart = 0;
2677                                         setAttr.length.HighPart = 0;
2678                                         code = cm_SetAttr(scp, &setAttr, userp,
2679                                                           &req);
2680                                 }
2681                         }       /* lookup succeeded */
2682                 }
2683         }
2684         
2685         /* we don't need this any longer */
2686         if (dscp) cm_ReleaseSCache(dscp);
2687
2688         if (code) {
2689                 /* something went wrong creating or truncating the file */
2690                 if (scp) cm_ReleaseSCache(scp);
2691                 cm_ReleaseUser(userp);
2692                 return code;
2693         }
2694         
2695         /* make sure we're about to open a file */
2696         if (scp->fileType != CM_SCACHETYPE_FILE) {
2697                 cm_ReleaseSCache(scp);
2698                 cm_ReleaseUser(userp);
2699                 return CM_ERROR_ISDIR;
2700         }
2701
2702         /* now all we have to do is open the file itself */
2703         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2704         osi_assert(fidp);
2705         
2706         /* save a pointer to the vnode */
2707         fidp->scp = scp;
2708         
2709         /* compute open mode */
2710         if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2711         if (openMode == 1 || openMode == 2)
2712                 fidp->flags |= SMB_FID_OPENWRITE;
2713
2714         smb_ReleaseFID(fidp);
2715         
2716         cm_Open(scp, 0, userp);
2717
2718         /* set inp->fid so that later read calls in same msg can find fid */
2719         inp->fid = fidp->fid;
2720         
2721         /* copy out remainder of the parms */
2722         parmSlot = 2;
2723         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2724         lock_ObtainMutex(&scp->mx);
2725         if (extraInfo) {
2726                 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2727                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2728                 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2729                 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2730                 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2731                 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2732                 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2733                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2734                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2735         }
2736         /* and the final "always present" stuff */
2737         smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2738         /* next write out the "unique" ID */
2739         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2740         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2741         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2742         lock_ReleaseMutex(&scp->mx);
2743         smb_SetSMBDataLength(outp, 0);
2744
2745         osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2746
2747         cm_ReleaseUser(userp);
2748         /* leave scp held since we put it in fidp->scp */
2749         return 0;
2750 }
2751
2752 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2753 {
2754         cm_req_t req;
2755         cm_user_t *userp;
2756         unsigned short fid;
2757         smb_fid_t *fidp;
2758         cm_scache_t *scp;
2759         unsigned char LockType;
2760         unsigned short NumberOfUnlocks, NumberOfLocks;
2761         unsigned long Timeout;
2762         char *op;
2763         LARGE_INTEGER LOffset, LLength;
2764         smb_waitingLock_t *waitingLock;
2765         void *lockp;
2766         long code;
2767         int i;
2768
2769         cm_InitReq(&req);
2770
2771         fid = smb_GetSMBParm(inp, 2);
2772         fid = smb_ChainFID(fid, inp);
2773
2774         fidp = smb_FindFID(vcp, fid, 0);
2775         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2776                 return CM_ERROR_BADFD;
2777         }
2778         /* set inp->fid so that later read calls in same msg can find fid */
2779         inp->fid = fid;
2780
2781         userp = smb_GetUser(vcp, inp);
2782
2783         scp = fidp->scp;
2784
2785         lock_ObtainMutex(&scp->mx);
2786         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2787                          CM_SCACHESYNC_NEEDCALLBACK
2788                          | CM_SCACHESYNC_GETSTATUS
2789                          | CM_SCACHESYNC_LOCK);
2790         if (code) goto doneSync;
2791
2792         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2793         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2794         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2795         NumberOfLocks = smb_GetSMBParm(inp, 7);
2796
2797         op = smb_GetSMBData(inp, NULL);
2798
2799         for (i=0; i<NumberOfUnlocks; i++) {
2800                 if (LockType & 0x10) {
2801                         /* Large Files */
2802                         LOffset.HighPart = *((LONG *)(op + 4));
2803                         LOffset.LowPart = *((DWORD *)(op + 8));
2804                         LLength.HighPart = *((LONG *)(op + 12));
2805                         LLength.LowPart = *((DWORD *)(op + 16));
2806                         op += 20;
2807                 }
2808                 else {
2809                         /* Not Large Files */
2810                         LOffset.HighPart = 0;
2811                         LOffset.LowPart = *((DWORD *)(op + 2));
2812                         LLength.HighPart = 0;
2813                         LLength.LowPart = *((DWORD *)(op + 6));
2814                         op += 10;
2815                 }
2816                 if (LargeIntegerNotEqualToZero(LOffset))
2817                         continue;
2818                 /* Do not check length -- length check done in cm_Unlock */
2819
2820                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2821                 if (code) goto done;
2822         }
2823
2824         for (i=0; i<NumberOfLocks; i++) {
2825                 if (LockType & 0x10) {
2826                         /* Large Files */
2827                         LOffset.HighPart = *((LONG *)(op + 4));
2828                         LOffset.LowPart = *((DWORD *)(op + 8));
2829                         LLength.HighPart = *((LONG *)(op + 12));
2830                         LLength.LowPart = *((DWORD *)(op + 16));
2831                         op += 20;
2832                 }
2833                 else {
2834                         /* Not Large Files */
2835                         LOffset.HighPart = 0;
2836                         LOffset.LowPart = *((DWORD *)(op + 2));
2837                         LLength.HighPart = 0;
2838                         LLength.LowPart = *((DWORD *)(op + 6));
2839                         op += 10;
2840                 }
2841                 if (LargeIntegerNotEqualToZero(LOffset))
2842                         continue;
2843                 if (LargeIntegerLessThan(LOffset, scp->length))
2844                         continue;
2845
2846                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2847                                 userp, &req, &lockp);
2848                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2849                         /* Put on waiting list */
2850                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2851                         waitingLock->vcp = vcp;
2852                         waitingLock->inp = smb_CopyPacket(inp);
2853                         waitingLock->outp = smb_CopyPacket(outp);
2854                         waitingLock->timeRemaining = Timeout;
2855                         waitingLock->lockp = lockp;
2856                         lock_ObtainWrite(&smb_globalLock);
2857                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2858                                  &waitingLock->q);
2859                         osi_Wakeup((long) &smb_allWaitingLocks);
2860                         lock_ReleaseWrite(&smb_globalLock);
2861                         /* don't send reply immediately */
2862                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2863                 }
2864                 if (code) break;
2865         }
2866
2867         if (code) {
2868                 /* release any locks acquired before the failure */
2869         }
2870         else
2871                 smb_SetSMBDataLength(outp, 0);
2872 done:
2873         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2874 doneSync:
2875         lock_ReleaseMutex(&scp->mx);
2876         cm_ReleaseUser(userp);
2877         smb_ReleaseFID(fidp);
2878
2879         return code;
2880 }
2881
2882 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2883 {
2884         unsigned short fid;
2885         smb_fid_t *fidp;
2886         cm_scache_t *scp;
2887         long code;
2888         long searchTime;
2889         cm_user_t *userp;
2890         cm_req_t req;
2891
2892         cm_InitReq(&req);
2893
2894         fid = smb_GetSMBParm(inp, 0);
2895         fid = smb_ChainFID(fid, inp);
2896         
2897         fidp = smb_FindFID(vcp, fid, 0);
2898         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2899                 return CM_ERROR_BADFD;
2900         }
2901         
2902         userp = smb_GetUser(vcp, inp);
2903         
2904         scp = fidp->scp;
2905         
2906         /* otherwise, stat the file */
2907         lock_ObtainMutex(&scp->mx);
2908         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2909                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2910         if (code) goto done;
2911
2912         /* decode times.  We need a search time, but the response to this
2913          * call provides the date first, not the time, as returned in the
2914          * searchTime variable.  So we take the high-order bits first.
2915          */
2916         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2917         smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);   /* ctime */
2918         smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2919         smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);   /* atime */
2920         smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2921         smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);   /* mtime */
2922         smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2923         
2924         /* now handle file size and allocation size */
2925         smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);          /* file size */
2926         smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2927         smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);          /* alloc size */
2928         smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2929         
2930         /* file attribute */
2931         smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2932         
2933         /* and finalize stuff */
2934         smb_SetSMBDataLength(outp, 0);
2935         code = 0;
2936
2937 done:
2938         lock_ReleaseMutex(&scp->mx);
2939         cm_ReleaseUser(userp);
2940         smb_ReleaseFID(fidp);
2941         return code;
2942 }
2943
2944 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2945 {
2946         unsigned short fid;
2947         smb_fid_t *fidp;
2948         cm_scache_t *scp;
2949         long code;
2950         long searchTime;
2951         long unixTime;
2952         cm_user_t *userp;
2953         cm_attr_t attrs;
2954         cm_req_t req;
2955
2956         cm_InitReq(&req);
2957
2958         fid = smb_GetSMBParm(inp, 0);
2959         fid = smb_ChainFID(fid, inp);
2960         
2961         fidp = smb_FindFID(vcp, fid, 0);
2962         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2963                 return CM_ERROR_BADFD;
2964         }
2965         
2966         userp = smb_GetUser(vcp, inp);
2967         
2968         scp = fidp->scp;
2969         
2970         /* now prepare to call cm_setattr.  This message only sets various times,
2971          * and AFS only implements mtime, and we'll set the mtime if that's
2972          * requested.  The others we'll ignore.
2973          */
2974         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2975         
2976         if (searchTime != 0) {
2977                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2978
2979             if ( unixTime != -1 ) {
2980                 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2981                 attrs.clientModTime = unixTime;
2982                 code = cm_SetAttr(scp, &attrs, userp, &req);
2983
2984                 osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2985             } else {
2986                 osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2987             }
2988         }
2989         else code = 0;
2990
2991         cm_ReleaseUser(userp);
2992         smb_ReleaseFID(fidp);
2993         return code;
2994 }
2995
2996
2997 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2998 {
2999         osi_hyper_t offset;
3000         long count, finalCount;
3001         unsigned short fd;
3002         smb_fid_t *fidp;
3003         long code;
3004         cm_user_t *userp;
3005         char *op;
3006         
3007         fd = smb_GetSMBParm(inp, 2);
3008         count = smb_GetSMBParm(inp, 5);
3009         offset.HighPart = 0;    /* too bad */
3010         offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3011         
3012         osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3013                 fd, offset.LowPart, count);
3014         
3015         fd = smb_ChainFID(fd, inp);
3016         fidp = smb_FindFID(vcp, fd, 0);
3017         if (!fidp) {
3018                 return CM_ERROR_BADFD;
3019         }
3020         /* set inp->fid so that later read calls in same msg can find fid */
3021         inp->fid = fd;
3022
3023         if (fidp->flags & SMB_FID_IOCTL) {
3024                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3025         }
3026         
3027         userp = smb_GetUser(vcp, inp);
3028
3029         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3030          * and will be further filled in after we return.
3031          */
3032         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
3033         smb_SetSMBParm(outp, 3, 0);     /* resvd */
3034         smb_SetSMBParm(outp, 4, 0);     /* resvd */
3035         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3036         /* fill in #6 when we have all the parameters' space reserved */
3037         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
3038         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
3039         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
3040         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
3041         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3042
3043         /* get op ptr after putting in the parms, since otherwise we don't
3044          * know where the data really is.
3045          */
3046         op = smb_GetSMBData(outp, NULL);
3047         
3048         /* now fill in offset from start of SMB header to first data byte (to op) */
3049         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3050
3051         /* set the packet data length the count of the # of bytes */
3052         smb_SetSMBDataLength(outp, count);
3053
3054 #ifndef DJGPP
3055         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3056 #else /* DJGPP */
3057         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3058 #endif /* !DJGPP */
3059
3060         /* fix some things up */
3061         smb_SetSMBParm(outp, 5, finalCount);
3062         smb_SetSMBDataLength(outp, finalCount);
3063
3064         smb_ReleaseFID(fidp);
3065
3066         cm_ReleaseUser(userp);
3067         return code;
3068 }
3069         
3070 /*
3071  * Values for createDisp, copied from NTDDK.H
3072  *
3073  *  FILE_SUPERSEDE      0       (???)
3074  *  FILE_OPEN           1       (open)
3075  *  FILE_CREATE         2       (exclusive)
3076  *  FILE_OPEN_IF        3       (non-exclusive)
3077  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3078  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3079  */
3080
3081 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3082 {
3083         char *pathp, *realPathp;
3084         long code;
3085         cm_space_t *spacep;
3086         cm_user_t *userp;
3087         cm_scache_t *dscp;              /* parent dir */
3088         cm_scache_t *scp;               /* file to create or open */
3089         cm_attr_t setAttr;
3090         char *lastNamep;
3091     char *treeStartp;
3092         unsigned short nameLength;
3093         unsigned int flags;
3094         unsigned int requestOpLock;
3095         unsigned int requestBatchOpLock;
3096         unsigned int mustBeDir;
3097     unsigned int treeCreate;
3098         int realDirFlag;
3099         unsigned int desiredAccess;
3100         unsigned int extAttributes;
3101         unsigned int createDisp;
3102         unsigned int createOptions;
3103         int initialModeBits;
3104         unsigned short baseFid;
3105         smb_fid_t *baseFidp;
3106         smb_fid_t *fidp;
3107         cm_scache_t *baseDirp;
3108         unsigned short openAction;
3109         int parmSlot;
3110         long fidflags;
3111         FILETIME ft;
3112         LARGE_INTEGER sz;
3113         char *tidPathp;
3114         BOOL foundscp;
3115         cm_req_t req;
3116
3117         cm_InitReq(&req);
3118
3119     treeCreate = FALSE;
3120         foundscp = FALSE;
3121         scp = NULL;
3122
3123         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3124         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3125                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3126         requestOpLock = flags & 0x02;
3127         requestBatchOpLock = flags & 0x04;
3128         mustBeDir = flags & 0x08;
3129
3130         /*
3131          * Why all of a sudden 32-bit FID?
3132          * We will reject all bits higher than 16.
3133          */
3134         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3135                 return CM_ERROR_INVAL;
3136         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3137         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3138                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3139         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3140                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3141         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3142                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3143         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3144                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3145
3146         /* mustBeDir is never set; createOptions directory bit seems to be
3147          * more important
3148          */
3149         if (createOptions & 1)
3150                 realDirFlag = 1;
3151         else if (createOptions & 0x40)
3152                 realDirFlag = 0;
3153         else
3154                 realDirFlag = -1;
3155
3156         /*
3157          * compute initial mode bits based on read-only flag in
3158          * extended attributes
3159          */
3160         initialModeBits = 0666;
3161         if (extAttributes & 1) initialModeBits &= ~0222;
3162
3163         pathp = smb_GetSMBData(inp, NULL);
3164         /* Sometimes path is not null-terminated, so we make a copy. */
3165         realPathp = malloc(nameLength+1);
3166         memcpy(realPathp, pathp, nameLength);
3167         realPathp[nameLength] = 0;
3168
3169         spacep = inp->spacep;
3170         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3171
3172     osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3173     osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3174
3175         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3176                 /* special case magic file name for receiving IOCTL requests
3177                  * (since IOCTL calls themselves aren't getting through).
3178                  */
3179                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3180                 smb_SetupIoctlFid(fidp, spacep);
3181
3182                 /* set inp->fid so that later read calls in same msg can find fid */
3183                 inp->fid = fidp->fid;
3184
3185                 /* out parms */
3186                 parmSlot = 2;
3187                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3188                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3189                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3190                 /* times */
3191                 memset(&ft, 0, sizeof(ft));
3192                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3193                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3194                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3195                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3196                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3197                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3198                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3199                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3200                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3201                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3202                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3203                 smb_SetSMBDataLength(outp, 0);
3204
3205                 /* clean up fid reference */
3206                 smb_ReleaseFID(fidp);
3207                 free(realPathp);
3208                 return 0;
3209         }
3210
3211 #ifdef DEBUG_VERBOSE
3212     {
3213         char *hexp, *asciip;
3214         asciip = (lastNamep? lastNamep : realPathp);
3215         hexp = osi_HexifyString( asciip );
3216         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3217         free(hexp);
3218     }
3219 #endif
3220     userp = smb_GetUser(vcp, inp);
3221     if (!userp) {
3222         osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3223         free(realPathp);
3224         return CM_ERROR_INVAL;
3225     }
3226
3227         if (baseFid == 0) {
3228                 baseDirp = cm_rootSCachep;
3229                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3230         }
3231         else {
3232         baseFidp = smb_FindFID(vcp, baseFid, 0);
3233         if (!baseFidp) {
3234                 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3235                 free(realPathp);
3236                 cm_ReleaseUser(userp);
3237                 return CM_ERROR_INVAL;
3238         }
3239                 baseDirp = baseFidp->scp;
3240                 tidPathp = NULL;
3241         }
3242
3243     osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3244         
3245     /* compute open mode */
3246         fidflags = 0;
3247         if (desiredAccess & DELETE)
3248                 fidflags |= SMB_FID_OPENDELETE;
3249         if (desiredAccess & AFS_ACCESS_READ)
3250                 fidflags |= SMB_FID_OPENREAD;
3251         if (desiredAccess & AFS_ACCESS_WRITE)
3252                 fidflags |= SMB_FID_OPENWRITE;
3253
3254         dscp = NULL;
3255         code = 0;
3256         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3257                         userp, tidPathp, &req, &scp);
3258         if (code == 0) foundscp = TRUE;
3259         if (code != 0
3260             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3261                 /* look up parent directory */
3262         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3263         the immediate parent.  We have to work our way up realPathp until we hit something that we
3264         recognize.
3265         */
3266
3267         while(1) {
3268             char *tp;
3269
3270             code = cm_NameI(baseDirp, spacep->data,
3271                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3272                              userp, tidPathp, &req, &dscp);
3273
3274             if(code && 
3275                 (tp = strrchr(spacep->data,'\\')) &&
3276                 (createDisp == 2) &&
3277                 (realDirFlag == 1)) {
3278                 *tp++ = 0;
3279                 treeCreate = TRUE;
3280                 treeStartp = realPathp + (tp - spacep->data);
3281
3282                 if(*tp && !smb_IsLegalFilename(tp)) {
3283                     if(baseFid != 0) smb_ReleaseFID(baseFidp);
3284                     cm_ReleaseUser(userp);
3285                     free(realPathp);
3286                     return CM_ERROR_BADNTFILENAME;
3287                 }
3288             }
3289             else
3290                 break;
3291         }
3292
3293         if (baseFid != 0) smb_ReleaseFID(baseFidp);
3294
3295         if (code) {
3296             osi_Log0(afsd_logp,"NTCreateX parent not found");
3297             cm_ReleaseUser(userp);
3298             free(realPathp);
3299             return code;
3300         }
3301
3302         if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3303             /* A file exists where we want a directory. */
3304             cm_ReleaseSCache(dscp);
3305             cm_ReleaseUser(userp);
3306             free(realPathp);
3307             return CM_ERROR_EXISTS;
3308         }
3309
3310         if (!lastNamep) lastNamep = realPathp;
3311         else lastNamep++;
3312
3313         if (!smb_IsLegalFilename(lastNamep)) {
3314             cm_ReleaseSCache(dscp);
3315             cm_ReleaseUser(userp);
3316             free(realPathp);
3317             return CM_ERROR_BADNTFILENAME;
3318         }
3319
3320         if (!foundscp && !treeCreate) {
3321                         code = cm_Lookup(dscp, lastNamep,
3322                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3323                                          userp, &req, &scp);
3324                         if (code && code != CM_ERROR_NOSUCHFILE) {
3325                                 cm_ReleaseSCache(dscp);
3326                                 cm_ReleaseUser(userp);
3327                                 free(realPathp);
3328                                 return code;
3329                         }
3330                 }
3331         }
3332         else {
3333                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3334         }
3335
3336         /* if we get here, if code is 0, the file exists and is represented by
3337          * scp.  Otherwise, we have to create it.  The dir may be represented
3338          * by dscp, or we may have found the file directly.  If code is non-zero,
3339          * scp is NULL.
3340          */
3341         if (code == 0 && !treeCreate) {
3342                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3343                                       &req);
3344                 if (code) {
3345                         if (dscp) cm_ReleaseSCache(dscp);
3346                         cm_ReleaseSCache(scp);
3347                         cm_ReleaseUser(userp);
3348                         free(realPathp);
3349                         return code;
3350                 }
3351
3352                 if (createDisp == 2) {
3353                         /* oops, file shouldn't be there */
3354                         if (dscp) cm_ReleaseSCache(dscp);
3355                         cm_ReleaseSCache(scp);
3356                         cm_ReleaseUser(userp);
3357                         free(realPathp);
3358                         return CM_ERROR_EXISTS;
3359                 }
3360
3361                 if (createDisp == 4
3362                     || createDisp == 5) {
3363                         setAttr.mask = CM_ATTRMASK_LENGTH;
3364                         setAttr.length.LowPart = 0;
3365                         setAttr.length.HighPart = 0;
3366                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3367                         openAction = 3; /* truncated existing file */
3368                 }
3369                 else openAction = 1;    /* found existing file */
3370         }
3371         else if (createDisp == 1 || createDisp == 4) {
3372                 /* don't create if not found */
3373                 if (dscp) cm_ReleaseSCache(dscp);
3374                 cm_ReleaseUser(userp);
3375                 free(realPathp);
3376                 return CM_ERROR_NOSUCHFILE;
3377         }
3378         else if (realDirFlag == 0 || realDirFlag == -1) {
3379                 osi_assert(dscp != NULL);
3380                 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3381                                 osi_LogSaveString(afsd_logp, lastNamep));
3382                 openAction = 2;         /* created file */
3383                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3384                 setAttr.clientModTime = time(NULL);
3385                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3386                                  &req);
3387                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3388                         smb_NotifyChange(FILE_ACTION_ADDED,
3389                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3390                                          dscp, lastNamep, NULL, TRUE);
3391                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3392                         /* Not an exclusive create, and someone else tried
3393                          * creating it already, then we open it anyway.  We
3394                          * don't bother retrying after this, since if this next
3395                          * fails, that means that the file was deleted after we
3396                          * started this call.
3397                          */
3398                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3399                                          userp, &req, &scp);
3400                         if (code == 0) {
3401                                 if (createDisp == 5) {
3402                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3403                                         setAttr.length.LowPart = 0;
3404                                         setAttr.length.HighPart = 0;
3405                                         code = cm_SetAttr(scp, &setAttr, userp,
3406                                                           &req);
3407                                 }
3408                         }       /* lookup succeeded */
3409                 }
3410         }
3411         else {
3412         char *tp, *pp;
3413         char *cp; /* This component */
3414         int clen; /* length of component */
3415         cm_scache_t *tscp;
3416         int isLast = 0;
3417                 
3418         /* create directory */
3419                 if ( !treeCreate ) treeStartp = lastNamep;
3420         osi_assert(dscp != NULL);
3421         osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3422                                 osi_LogSaveString(afsd_logp, treeStartp));
3423                 openAction = 2;         /* created directory */
3424
3425                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3426                 setAttr.clientModTime = time(NULL);
3427                 
3428                 pp = treeStartp;
3429                 cp = spacep->data;
3430                 tscp = dscp;
3431
3432                 while(pp && *pp) {
3433                         tp = strchr(pp, '\\');
3434                         if(!tp) {
3435                                 strcpy(cp,pp);
3436                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
3437                         }
3438                         else {
3439                                 clen = tp - pp;
3440                                 strncpy(cp,pp,clen);
3441                                 *(cp + clen) = 0;
3442                                 tp++;
3443                         }
3444                         pp = tp;
3445
3446                         if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3447
3448                         /* cp is the next component to be created. */
3449                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3450                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3451                                 smb_NotifyChange(FILE_ACTION_ADDED,
3452                                 FILE_NOTIFY_CHANGE_DIR_NAME,
3453                                 tscp, cp, NULL, TRUE);
3454                         if (code == 0 || 
3455                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3456                                         /* Not an exclusive create, and someone else tried
3457                                         * creating it already, then we open it anyway.  We
3458                                         * don't bother retrying after this, since if this next
3459                                         * fails, that means that the file was deleted after we
3460                                         * started this call.
3461                                         */
3462                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3463                                                 userp, &req, &scp);
3464                                 }
3465                         if(code) break;
3466
3467                         if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3468                                 cm_ReleaseSCache(tscp);
3469                                 tscp = scp; /* Newly created directory will be next parent */
3470                         }
3471                 }
3472
3473                 /* 
3474                 if we get here and code == 0, then scp is the last directory created, and tscp is the
3475                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
3476                 */
3477                 dscp = tscp;
3478         }
3479
3480         if (code) {
3481                 /* something went wrong creating or truncating the file */
3482                 if (scp) cm_ReleaseSCache(scp);
3483         if (dscp) cm_ReleaseSCache(dscp);
3484                 cm_ReleaseUser(userp);
3485                 free(realPathp);
3486                 return code;
3487         }
3488
3489         /* make sure we have file vs. dir right (only applies for single component case) */
3490         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3491                 cm_ReleaseSCache(scp);
3492         if (dscp) cm_ReleaseSCache(dscp);
3493                 cm_ReleaseUser(userp);
3494                 free(realPathp);
3495                 return CM_ERROR_ISDIR;
3496         }
3497     /* (only applies to single component case) */
3498         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3499                 cm_ReleaseSCache(scp);
3500         if (dscp) cm_ReleaseSCache(dscp);
3501                 cm_ReleaseUser(userp);
3502                 free(realPathp);
3503                 return CM_ERROR_NOTDIR;
3504         }
3505
3506         /* open the file itself */
3507         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3508         osi_assert(fidp);
3509         /* save a pointer to the vnode */
3510         fidp->scp = scp;
3511
3512         fidp->flags = fidflags;
3513
3514         /* save parent dir and pathname for delete or change notification */
3515         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3516                 fidp->flags |= SMB_FID_NTOPEN;
3517                 fidp->NTopen_dscp = dscp;
3518                 cm_HoldSCache(dscp);
3519                 fidp->NTopen_pathp = strdup(lastNamep);
3520         }
3521         fidp->NTopen_wholepathp = realPathp;
3522
3523         /* we don't need this any longer */
3524         if (dscp) cm_ReleaseSCache(dscp);
3525         cm_Open(scp, 0, userp);
3526
3527         /* set inp->fid so that later read calls in same msg can find fid */
3528         inp->fid = fidp->fid;
3529
3530         /* out parms */
3531         parmSlot = 2;
3532         lock_ObtainMutex(&scp->mx);
3533         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3534         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3535         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3536         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3537         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3538         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3539         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3540         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3541         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3542                                                 parmSlot += 2;
3543         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3544         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3545         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3546         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3547         smb_SetSMBParmByte(outp, parmSlot,
3548                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3549         lock_ReleaseMutex(&scp->mx);
3550         smb_SetSMBDataLength(outp, 0);
3551
3552         osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3553                  osi_LogSaveString(afsd_logp, realPathp));
3554
3555         smb_ReleaseFID(fidp);
3556
3557         cm_ReleaseUser(userp);
3558
3559     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3560
3561         /* leave scp held since we put it in fidp->scp */
3562         return 0;
3563 }
3564
3565 /*
3566  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3567  * Instead, ultimately, would like to use a subroutine for common code.
3568  */
3569 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3570 {
3571         char *pathp, *realPathp;
3572         long code;
3573         cm_space_t *spacep;
3574         cm_user_t *userp;
3575         cm_scache_t *dscp;              /* parent dir */
3576         cm_scache_t *scp;               /* file to create or open */
3577         cm_attr_t setAttr;
3578         char *lastNamep;
3579         unsigned long nameLength;
3580         unsigned int flags;
3581         unsigned int requestOpLock;
3582         unsigned int requestBatchOpLock;
3583         unsigned int mustBeDir;
3584     unsigned int extendedRespRequired;
3585         int realDirFlag;
3586         unsigned int desiredAccess;
3587 #ifdef DEBUG_VERBOSE    
3588     unsigned int allocSize;
3589     unsigned int shareAccess;
3590 #endif
3591         unsigned int extAttributes;
3592         unsigned int createDisp;
3593 #ifdef DEBUG_VERBOSE
3594     unsigned int sdLen;
3595 #endif
3596         unsigned int createOptions;
3597         int initialModeBits;
3598         unsigned short baseFid;
3599         smb_fid_t *baseFidp;
3600         smb_fid_t *fidp;
3601         cm_scache_t *baseDirp;
3602         unsigned short openAction;
3603         int parmSlot;
3604         long fidflags;
3605         FILETIME ft;
3606         char *tidPathp;
3607         BOOL foundscp;
3608         int parmOffset, dataOffset;
3609         char *parmp;
3610         ULONG *lparmp;
3611         char *outData;
3612         cm_req_t req;
3613
3614         cm_InitReq(&req);
3615
3616         foundscp = FALSE;
3617         scp = NULL;
3618
3619         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3620                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3621         parmp = inp->data + parmOffset;
3622         lparmp = (ULONG *) parmp;
3623
3624         flags = lparmp[0];
3625         requestOpLock = flags & 0x02;
3626         requestBatchOpLock = flags & 0x04;
3627         mustBeDir = flags & 0x08;
3628     extendedRespRequired = flags & 0x10;
3629
3630         /*
3631          * Why all of a sudden 32-bit FID?
3632          * We will reject all bits higher than 16.
3633          */
3634         if (lparmp[1] & 0xFFFF0000)
3635                 return CM_ERROR_INVAL;
3636         baseFid = (unsigned short)lparmp[1];
3637         desiredAccess = lparmp[2];
3638 #ifdef DEBUG_VERBOSE
3639     allocSize = lparmp[3];
3640 #endif /* DEBUG_VERSOSE */
3641         extAttributes = lparmp[5];
3642 #ifdef DEBUG_VEROSE
3643     shareAccess = lparmp[6];
3644 #endif
3645         createDisp = lparmp[7];
3646         createOptions = lparmp[8];
3647 #ifdef DEBUG_VERBOSE
3648     sdLen = lparmp[9];
3649 #endif
3650         nameLength = lparmp[11];
3651
3652 #ifdef DEBUG_VERBOSE
3653         osi_Log4(afsd_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3654         osi_Log2(afsd_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3655         osi_Log1(afsd_logp,"... flags[%x]",flags);
3656 #endif
3657
3658         /* mustBeDir is never set; createOptions directory bit seems to be
3659          * more important
3660          */
3661         if (createOptions & 1)
3662                 realDirFlag = 1;
3663         else if (createOptions & 0x40)
3664                 realDirFlag = 0;
3665         else
3666                 realDirFlag = -1;
3667
3668         /*
3669          * compute initial mode bits based on read-only flag in
3670          * extended attributes
3671          */
3672         initialModeBits = 0666;
3673         if (extAttributes & 1) initialModeBits &= ~0222;
3674
3675         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3676         /* Sometimes path is not null-terminated, so we make a copy. */
3677         realPathp = malloc(nameLength+1);
3678         memcpy(realPathp, pathp, nameLength);
3679         realPathp[nameLength] = 0;
3680
3681         spacep = cm_GetSpace();
3682         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3683
3684         /*
3685          * Nothing here to handle SMB_IOCTL_FILENAME.
3686          * Will add it if necessary.
3687          */
3688
3689 #ifdef DEBUG_VERBOSE
3690         {
3691                 char *hexp, *asciip;
3692                 asciip = (lastNamep? lastNamep : realPathp);
3693                 hexp = osi_HexifyString( asciip );
3694                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3695                 free(hexp);
3696         }
3697 #endif
3698
3699         userp = smb_GetUser(vcp, inp);
3700     if(!userp) {
3701         osi_Log1(afsd_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3702         free(realPathp);
3703         return CM_ERROR_INVAL;
3704     }
3705
3706         if (baseFid == 0) {
3707                 baseDirp = cm_rootSCachep;
3708                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3709         }
3710         else {
3711         baseFidp = smb_FindFID(vcp, baseFid, 0);
3712         if(!baseFidp) {
3713                 osi_Log1(afsd_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3714                 free(realPathp);
3715                 cm_ReleaseUser(userp);
3716                 return CM_ERROR_INVAL;
3717         }
3718                 baseDirp = baseFidp->scp;
3719                 tidPathp = NULL;
3720         }
3721
3722         /* compute open mode */
3723         fidflags = 0;
3724         if (desiredAccess & DELETE)
3725                 fidflags |= SMB_FID_OPENDELETE;
3726         if (desiredAccess & AFS_ACCESS_READ)
3727                 fidflags |= SMB_FID_OPENREAD;
3728         if (desiredAccess & AFS_ACCESS_WRITE)
3729                 fidflags |= SMB_FID_OPENWRITE;
3730
3731         dscp = NULL;
3732         code = 0;
3733         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3734                         userp, tidPathp, &req, &scp);
3735         if (code == 0) foundscp = TRUE;
3736         if (code != 0
3737             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3738                 /* look up parent directory */
3739                 code = cm_NameI(baseDirp, spacep->data,
3740                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3741                                 userp, tidPathp, &req, &dscp);
3742                 cm_FreeSpace(spacep);
3743
3744                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3745
3746                 if (code) {
3747                         cm_ReleaseUser(userp);
3748                         free(realPathp);
3749                         return code;
3750                 }
3751
3752                 if (!lastNamep) lastNamep = realPathp;
3753                 else lastNamep++;
3754
3755                 if (!smb_IsLegalFilename(lastNamep))
3756                         return CM_ERROR_BADNTFILENAME;
3757
3758                 if (!foundscp) {
3759                         code = cm_Lookup(dscp, lastNamep,
3760                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3761                                          userp, &req, &scp);
3762                         if (code && code != CM_ERROR_NOSUCHFILE) {
3763                                 cm_ReleaseSCache(dscp);
3764                                 cm_ReleaseUser(userp);
3765                                 free(realPathp);
3766                                 return code;
3767                         }
3768                 }
3769         }
3770         else {
3771                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3772                 cm_FreeSpace(spacep);
3773         }
3774
3775         /* if we get here, if code is 0, the file exists and is represented by
3776          * scp.  Otherwise, we have to create it.  The dir may be represented
3777          * by dscp, or we may have found the file directly.  If code is non-zero,
3778          * scp is NULL.
3779          */
3780         if (code == 0) {
3781                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3782                                       &req);
3783                 if (code) {
3784                         if (dscp) cm_ReleaseSCache(dscp);
3785                         cm_ReleaseSCache(scp);
3786                         cm_ReleaseUser(userp);
3787                         free(realPathp);
3788                         return code;
3789                 }
3790
3791                 if (createDisp == 2) {
3792                         /* oops, file shouldn't be there */
3793                         if (dscp) cm_ReleaseSCache(dscp);
3794                         cm_ReleaseSCache(scp);
3795                         cm_ReleaseUser(userp);
3796                         free(realPathp);
3797                         return CM_ERROR_EXISTS;
3798                 }
3799
3800                 if (createDisp == 4
3801                     || createDisp == 5) {
3802                         setAttr.mask = CM_ATTRMASK_LENGTH;
3803                         setAttr.length.LowPart = 0;
3804                         setAttr.length.HighPart = 0;
3805                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3806                         openAction = 3; /* truncated existing file */
3807                 }
3808                 else openAction = 1;    /* found existing file */
3809         }
3810         else if (createDisp == 1 || createDisp == 4) {
3811                 /* don't create if not found */
3812                 if (dscp) cm_ReleaseSCache(dscp);
3813                 cm_ReleaseUser(userp);
3814                 free(realPathp);
3815                 return CM_ERROR_NOSUCHFILE;
3816         }
3817         else if (realDirFlag == 0 || realDirFlag == -1) {
3818                 osi_assert(dscp != NULL);
3819                 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3820                                 osi_LogSaveString(afsd_logp, lastNamep));
3821                 openAction = 2;         /* created file */
3822                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3823                 setAttr.clientModTime = time(NULL);
3824                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3825                                  &req);
3826                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3827                         smb_NotifyChange(FILE_ACTION_ADDED,
3828                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3829                                          dscp, lastNamep, NULL, TRUE);
3830                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3831                         /* Not an exclusive create, and someone else tried
3832                          * creating it already, then we open it anyway.  We
3833                          * don't bother retrying after this, since if this next
3834                          * fails, that means that the file was deleted after we
3835                          * started this call.
3836                          */
3837                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3838                                          userp, &req, &scp);
3839                         if (code == 0) {
3840                                 if (createDisp == 5) {
3841                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3842                                         setAttr.length.LowPart = 0;
3843                                         setAttr.length.HighPart = 0;
3844                                         code = cm_SetAttr(scp, &setAttr, userp,
3845                                                           &req);
3846                                 }
3847                         }       /* lookup succeeded */
3848                 }
3849         }
3850         else {
3851                 /* create directory */
3852                 osi_assert(dscp != NULL);
3853                 osi_Log1(afsd_logp,
3854                                 "smb_ReceiveNTTranCreate creating directory %s",
3855                                 osi_LogSaveString(afsd_logp, lastNamep));
3856                 openAction = 2;         /* created directory */
3857                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3858                 setAttr.clientModTime = time(NULL);
3859                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3860                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3861                         smb_NotifyChange(FILE_ACTION_ADDED,
3862                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3863                                          dscp, lastNamep, NULL, TRUE);
3864                 if (code == 0
3865                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3866                         /* Not an exclusive create, and someone else tried
3867                          * creating it already, then we open it anyway.  We
3868                          * don't bother retrying after this, since if this next
3869                          * fails, that means that the file was deleted after we
3870                          * started this call.
3871                          */
3872                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3873                                          userp, &req, &scp);
3874                 }
3875         }
3876
3877         if (code) {
3878                 /* something went wrong creating or truncating the file */
3879                 if (scp) cm_ReleaseSCache(scp);
3880                 cm_ReleaseUser(userp);
3881                 free(realPathp);
3882                 return code;
3883         }
3884
3885         /* make sure we have file vs. dir right */
3886         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3887                 cm_ReleaseSCache(scp);
3888                 cm_ReleaseUser(userp);
3889                 free(realPathp);
3890                 return CM_ERROR_ISDIR;
3891         }
3892         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3893                 cm_ReleaseSCache(scp);
3894                 cm_ReleaseUser(userp);
3895                 free(realPathp);
3896                 return CM_ERROR_NOTDIR;
3897         }
3898
3899         /* open the file itself */
3900         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3901         osi_assert(fidp);
3902
3903         /* save a pointer to the vnode */
3904         fidp->scp = scp;
3905
3906         fidp->flags = fidflags;
3907
3908         /* save parent dir and pathname for deletion or change notification */
3909         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3910                 fidp->flags |= SMB_FID_NTOPEN;
3911                 fidp->NTopen_dscp = dscp;
3912                 cm_HoldSCache(dscp);
3913                 fidp->NTopen_pathp = strdup(lastNamep);
3914         }
3915         fidp->NTopen_wholepathp = realPathp;
3916
3917         /* we don't need this any longer */
3918         if (dscp) cm_ReleaseSCache(dscp);
3919
3920         cm_Open(scp, 0, userp);
3921
3922         /* set inp->fid so that later read calls in same msg can find fid */
3923         inp->fid = fidp->fid;
3924
3925     /* check whether we are required to send an extended response */
3926     if (!extendedRespRequired) {
3927         /* out parms */
3928         parmOffset = 8*4 + 39;
3929         parmOffset += 1;        /* pad to 4 */
3930         dataOffset = parmOffset + 70;
3931
3932         parmSlot = 1;
3933         outp->oddByte = 1;
3934         /* Total Parameter Count */
3935         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3936         /* Total Data Count */
3937         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3938         /* Parameter Count */
3939         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3940         /* Parameter Offset */
3941         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3942         /* Parameter Displacement */
3943         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3944         /* Data Count */
3945         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3946         /* Data Offset */
3947         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3948         /* Data Displacement */
3949         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3950         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
3951         smb_SetSMBDataLength(outp, 70);
3952
3953         lock_ObtainMutex(&scp->mx);
3954         outData = smb_GetSMBData(outp, NULL);
3955         outData++;                      /* round to get to parmOffset */
3956         *outData = 0; outData++;        /* oplock */
3957         *outData = 0; outData++;        /* reserved */
3958         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3959         *((ULONG *)outData) = openAction; outData += 4;
3960         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
3961         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3962         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
3963         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
3964         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
3965         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
3966         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3967         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3968         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3969         *((USHORT *)outData) = 0; outData += 2; /* filetype */
3970         *((USHORT *)outData) = 0; outData += 2; /* dev state */
3971         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3972         outData += 2;   /* is a dir? */
3973         lock_ReleaseMutex(&scp->mx);
3974     } else {
3975         /* out parms */
3976         parmOffset = 8*4 + 39;
3977         parmOffset += 1;        /* pad to 4 */
3978         dataOffset = parmOffset + 104;
3979         
3980         parmSlot = 1;
3981         outp->oddByte = 1;
3982         /* Total Parameter Count */
3983         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
3984         /* Total Data Count */
3985         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3986         /* Parameter Count */
3987         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
3988         /* Parameter Offset */
3989         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3990         /* Parameter Displacement */
3991         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3992         /* Data Count */
3993         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3994         /* Data Offset */
3995         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3996         /* Data Displacement */
3997         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3998         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
3999         smb_SetSMBDataLength(outp, 105);
4000         
4001         lock_ObtainMutex(&scp->mx);
4002         outData = smb_GetSMBData(outp, NULL);
4003         outData++;                      /* round to get to parmOffset */
4004         *outData = 0; outData++;        /* oplock */
4005         *outData = 1; outData++;        /* response type */
4006         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4007         *((ULONG *)outData) = openAction; outData += 4;
4008         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4009         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4010         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4011         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4012         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4013         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4014         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4015         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4016         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4017         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4018         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4019         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4020         outData += 1;   /* is a dir? */
4021         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4022         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4023         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4024         lock_ReleaseMutex(&scp->mx);
4025     }
4026
4027         osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4028
4029         smb_ReleaseFID(fidp);
4030
4031         cm_ReleaseUser(userp);
4032
4033         /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4034         /* leave scp held since we put it in fidp->scp */
4035         return 0;
4036 }
4037
4038 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4039         smb_packet_t *outp)
4040 {
4041         smb_packet_t *savedPacketp;
4042         ULONG filter; USHORT fid, watchtree;
4043         smb_fid_t *fidp;
4044         cm_scache_t *scp;
4045         
4046         filter = smb_GetSMBParm(inp, 19)
4047                         | (smb_GetSMBParm(inp, 20) << 16);
4048         fid = smb_GetSMBParm(inp, 21);
4049         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
4050
4051     fidp = smb_FindFID(vcp, fid, 0);
4052     if (!fidp) {
4053         osi_Log1(afsd_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4054         return CM_ERROR_BADFD;
4055     }
4056
4057         savedPacketp = smb_CopyPacket(inp);
4058         savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4059         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4060         savedPacketp->nextp = smb_Directory_Watches;
4061         smb_Directory_Watches = savedPacketp;
4062         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4063
4064         fidp = smb_FindFID(vcp, fid, 0);
4065                 
4066     if (fidp) {
4067         osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4068                  filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4069
4070         scp = fidp->scp;
4071         lock_ObtainMutex(&scp->mx);
4072         if (watchtree)
4073             scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4074         else
4075             scp->flags |= CM_SCACHEFLAG_WATCHED;
4076         lock_ReleaseMutex(&scp->mx);
4077         smb_ReleaseFID(fidp);
4078     }
4079     else 
4080     {
4081         /* nothing - just a warning to main log file ... */
4082         afsi_log("Warning: cannot find fidp vcp = 0x%X, fid = %d", vcp, fid);
4083     }
4084
4085         outp->flags |= SMB_PACKETFLAG_NOSEND;
4086
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