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