windows-afscache-validate-20050806
[openafs.git] / src / WINNT / afsd / cm_ioctl.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #else
16 #include <sys/socket.h>
17 #endif /* !DJGPP */
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <malloc.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <time.h>
24
25 #include <osi.h>
26
27 #include "afsd.h"
28 #include "afsd_init.h"
29 #include <WINNT\afsreg.h>
30
31 #include "smb.h"
32 #include "cm_server.h"
33
34 #ifndef DJGPP
35 #include <rx/rxkad.h>
36 #include "afsrpc.h"
37 #else
38 #include <rx/rxkad.h>
39 #include "afsrpc95.h"
40 #endif
41
42 #include "cm_rpc.h"
43 #include <strsafe.h>
44 #include <winioctl.h>
45 #include <..\afsrdr\kif.h>
46
47 #ifdef _DEBUG
48 #include <crtdbg.h>
49 #endif
50
51 /* Copied from afs_tokens.h */
52 #define PIOCTL_LOGON    0x1
53 #define MAX_PATH 260
54
55 osi_mutex_t cm_Afsdsbmt_Lock;
56
57 extern afs_int32 cryptall;
58 extern char cm_NetbiosName[];
59
60 extern void afsi_log(char *pattern, ...);
61
62 void cm_InitIoctl(void)
63 {
64     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
65 }
66
67 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
68 {
69     long code;
70
71     lock_ObtainWrite(&scp->bufCreateLock);
72     code = buf_FlushCleanPages(scp, userp, reqp);
73         
74     lock_ObtainMutex(&scp->mx);
75     scp->cbServerp = NULL;
76     scp->cbExpires = 0;
77     cm_dnlcPurgedp(scp);
78     cm_dnlcPurgevp(scp);
79     cm_FreeAllACLEnts(scp);
80     lock_ReleaseMutex(&scp->mx);
81
82     lock_ReleaseWrite(&scp->bufCreateLock);
83     return code;
84 }
85
86 /*
87  * cm_ResetACLCache -- invalidate ACL info for a user that has just
88  *                      obtained or lost tokens
89  */
90 void cm_ResetACLCache(cm_user_t *userp)
91 {
92     cm_scache_t *scp;
93     int hash;
94
95     lock_ObtainWrite(&cm_scacheLock);
96     for (hash=0; hash < cm_data.hashTableSize; hash++) {
97         for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
98             cm_HoldSCacheNoLock(scp);
99             lock_ReleaseWrite(&cm_scacheLock);
100             lock_ObtainMutex(&scp->mx);
101             cm_InvalidateACLUser(scp, userp);
102             lock_ReleaseMutex(&scp->mx);
103             lock_ObtainWrite(&cm_scacheLock);
104             cm_ReleaseSCacheNoLock(scp);
105         }
106     }
107     lock_ReleaseWrite(&cm_scacheLock);
108 }       
109
110 /*
111  *  TranslateExtendedChars - This is a fix for TR 54482.
112  *
113  *  If an extended character (80 - FF) is entered into a file
114  *  or directory name in Windows, the character is translated
115  *  into the OEM character map before being passed to us.  Why
116  *  this occurs is unknown.  Our pioctl functions must match
117  *  this translation for paths given via our own commands (like
118  *  fs).  If we do not do this, then we will try to perform an
119  *  operation on a non-translated path, which we will fail to 
120  *  find, since the path was created with the translated chars.
121  *  This function performs the required translation.
122  */
123 void TranslateExtendedChars(char *str)
124 {
125 #ifdef DJGPP
126     char *p;
127 #endif
128
129     if (!str || !*str)
130         return;
131
132 #ifndef DJGPP
133     CharToOem(str, str);
134 #else
135     p = str;
136     while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
137 #endif
138 }
139         
140 /* parse the passed-in file name and do a namei on it.  If we fail,
141  * return an error code, otherwise return the vnode located in *scpp.
142  */
143 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
144         cm_scache_t **scpp)
145 {
146     long code, length;
147     cm_scache_t *substRootp;
148     char * relativePath = ioctlp->inDatap, absRoot[MAX_PATH];
149         wchar_t absRoot_w[MAX_PATH];
150         HANDLE rootDir;
151
152     /* This is usually the file name, but for StatMountPoint it is the path. */
153     /* ioctlp->inDatap can be either of the form:
154      *    \path\.
155      *    \path\file
156      *    \\netbios-name\submount\path\.
157      *    \\netbios-name\submount\path\file
158      */
159     TranslateExtendedChars(relativePath);
160
161 #ifdef AFSIFS
162     /* we have passed the whole path, including the afs prefix.
163            when the pioctl call is made, we perform an ioctl to afsrdr
164            and it returns the correct (full) path.  therefore, there is
165            no drive letter, and the path is absolute. */
166     code = cm_NameI(cm_data.rootSCachep, relativePath,
167                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
168                      userp, "", reqp, scpp);
169
170     if (code)
171         return code;
172
173     /* # of bytes of path */
174     code = strlen(ioctlp->inDatap) + 1;
175     ioctlp->inDatap += code;
176
177     /* This is usually nothing, but for StatMountPoint it is the file name. */
178     TranslateExtendedChars(ioctlp->inDatap);
179
180     return 0;
181 #endif /* AFSIFS */
182
183     if (relativePath[0] == relativePath[1] &&
184          relativePath[1] == '\\' && 
185          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
186     {
187         char shareName[256];
188         char *sharePath;
189         int shareFound, i;
190
191         /* We may have found a UNC path. 
192          * If the first component is the NetbiosName,
193          * then throw out the second component (the submount)
194          * since it had better expand into the value of ioctl->tidPathp
195          */
196         char * p;
197         p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                      /* buffer overflow vuln.? */
198         if ( !_strnicmp("all", p, 3) )
199             p += 4;
200
201         for (i = 0; *p && *p != '\\'; i++,p++ ) {
202             shareName[i] = *p;
203         }
204         p++;                    /* skip past trailing slash */
205         shareName[i] = 0;       /* terminate string */
206
207         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
208         if ( shareFound ) {
209             /* we found a sharename, therefore use the resulting path */
210             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
211                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
212                              userp, sharePath, reqp, &substRootp);
213             free(sharePath);
214             if (code) 
215                 return code;
216
217             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
218                              userp, NULL, reqp, scpp);
219             if (code) 
220                 return code;
221         } else {
222             /* otherwise, treat the name as a cellname mounted off the afs root.
223              * This requires that we reconstruct the shareName string with 
224              * leading and trailing slashes.
225              */
226             p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
227             if ( !_strnicmp("all", p, 3) )
228                 p += 4;
229
230             shareName[0] = '/';
231             for (i = 1; *p && *p != '\\'; i++,p++ ) {
232                 shareName[i] = *p;
233             }
234             p++;                    /* skip past trailing slash */
235             shareName[i++] = '/';       /* add trailing slash */
236             shareName[i] = 0;       /* terminate string */
237
238
239             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
240                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
241                              userp, shareName, reqp, &substRootp);
242             if (code) 
243                 return code;
244
245             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
246                             userp, NULL, reqp, scpp);
247             if (code) 
248                 return code;
249         }
250     } else {
251         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
252                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
253                          userp, ioctlp->tidPathp, reqp, &substRootp);
254         if (code) 
255             return code;
256         
257         code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
258                          userp, NULL, reqp, scpp);
259         if (code) 
260             return code;
261     }
262
263     /* # of bytes of path */
264     code = strlen(ioctlp->inDatap) + 1;
265     ioctlp->inDatap += code;
266
267     /* This is usually nothing, but for StatMountPoint it is the file name. */
268     TranslateExtendedChars(ioctlp->inDatap);
269
270     /* and return success */
271     return 0;
272 }
273
274 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
275 {
276     long temp;
277         
278     temp = strlen(ioctlp->inDatap) + 1;
279     ioctlp->inDatap += temp;
280 }       
281
282
283 /* format the specified path to look like "/afs/<cellname>/usr", by
284  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
285  * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
286  * intentionally returned as "/afs/"--this makes submount manipulation
287  * easier (because we can always jump past the initial "/afs" to find
288  * the AFS path that should be written into afsdsbmt.ini).
289  */
290 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
291 {
292     char *cp;
293     char bslash_mountRoot[256];
294        
295     strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
296     bslash_mountRoot[0] = '\\';
297        
298     if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
299         StringCbCopy(outpathp, outlen, inpathp);
300     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
301         StringCbCopy(outpathp, outlen, inpathp);
302     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
303         StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
304     else // inpathp looks like "<cell>/usr"
305         StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
306
307     for (cp = outpathp; *cp != 0; ++cp) {
308         if (*cp == '\\')
309             *cp = '/';
310     }       
311
312     if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
313         outpathp[strlen(outpathp)-1] = 0;
314     }
315
316     if (!strcmpi (outpathp, cm_mountRoot)) {
317         StringCbCopy(outpathp, outlen, cm_mountRoot);
318     }
319 }
320
321 #define LEAF_SIZE 256
322 /* parse the passed-in file name and do a namei on its parent.  If we fail,
323  * return an error code, otherwise return the vnode located in *scpp.
324  */
325 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
326                          cm_scache_t **scpp, char *leafp)
327 {
328     long code;
329     char tbuffer[1024];
330     char *tp, *jp;
331     cm_scache_t *substRootp;
332
333     StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
334     tp = strrchr(tbuffer, '\\');
335     jp = strrchr(tbuffer, '/');
336     if (!tp)
337         tp = jp;
338     else if (jp && (tp - tbuffer) < (jp - tbuffer))
339         tp = jp;
340     if (!tp) {
341         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
342         if (leafp) 
343             StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
344     }
345     else {
346         *tp = 0;
347         if (leafp) 
348             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
349     }   
350
351     if (tbuffer[0] == tbuffer[1] &&
352         tbuffer[1] == '\\' && 
353         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
354     {
355         char shareName[256];
356         char *sharePath;
357         int shareFound, i;
358
359         /* We may have found a UNC path. 
360          * If the first component is the NetbiosName,
361          * then throw out the second component (the submount)
362          * since it had better expand into the value of ioctl->tidPathp
363          */
364         char * p;
365         p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
366         if ( !_strnicmp("all", p, 3) )
367             p += 4;
368
369         for (i = 0; *p && *p != '\\'; i++,p++ ) {
370             shareName[i] = *p;
371         }
372         p++;                    /* skip past trailing slash */
373         shareName[i] = 0;       /* terminate string */
374
375         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
376         if ( shareFound ) {
377             /* we found a sharename, therefore use the resulting path */
378             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
379                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
380                              userp, sharePath, reqp, &substRootp);
381             free(sharePath);
382             if (code) return code;
383
384             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
385                              userp, NULL, reqp, scpp);
386             if (code) return code;
387         } else {
388             /* otherwise, treat the name as a cellname mounted off the afs root.
389              * This requires that we reconstruct the shareName string with 
390              * leading and trailing slashes.
391              */
392             p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
393             if ( !_strnicmp("all", p, 3) )
394                 p += 4;
395
396             shareName[0] = '/';
397             for (i = 1; *p && *p != '\\'; i++,p++ ) {
398                 shareName[i] = *p;
399             }
400             p++;                    /* skip past trailing slash */
401             shareName[i++] = '/';       /* add trailing slash */
402             shareName[i] = 0;       /* terminate string */
403
404             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
405                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
406                              userp, shareName, reqp, &substRootp);
407             if (code) return code;
408
409             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
410                             userp, NULL, reqp, scpp);
411             if (code) return code;
412         }
413     } else {
414         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
415                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
416                         userp, ioctlp->tidPathp, reqp, &substRootp);
417         if (code) return code;
418
419         code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
420                         userp, NULL, reqp, scpp);
421         if (code) return code;
422     }
423
424     /* # of bytes of path */
425     code = strlen(ioctlp->inDatap) + 1;
426     ioctlp->inDatap += code;
427
428     /* and return success */
429     return 0;
430 }
431
432 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
433 {
434     cm_conn_t *connp;
435     cm_scache_t *scp;
436     AFSOpaque acl;
437     AFSFetchStatus fileStatus;
438     AFSVolSync volSync;
439     long code;
440     AFSFid fid;
441     int tlen;
442     cm_req_t req;
443     struct rx_connection * callp;
444
445     cm_InitReq(&req);
446
447     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
448     if (code) return code;
449
450     /* now make the get acl call */
451     fid.Volume = scp->fid.volume;
452     fid.Vnode = scp->fid.vnode;
453     fid.Unique = scp->fid.unique;
454     do {
455         acl.AFSOpaque_val = ioctlp->outDatap;
456         acl.AFSOpaque_len = 0;
457         code = cm_Conn(&scp->fid, userp, &req, &connp);
458         if (code) continue;
459
460         callp = cm_GetRxConn(connp);
461         code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
462         rx_PutConnection(callp);
463
464     } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
465     code = cm_MapRPCError(code, &req);
466     cm_ReleaseSCache(scp);
467
468     if (code) return code;
469
470     /* skip over return data */
471     tlen = strlen(ioctlp->outDatap) + 1;
472     ioctlp->outDatap += tlen;
473
474     /* and return success */
475     return 0;
476 }
477
478 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
479 {
480     long code;
481     cm_scache_t *scp;
482     cm_cell_t *cellp;
483     cm_req_t req;
484
485     cm_InitReq(&req);
486
487     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
488     if (code) return code;
489
490 #ifdef AFS_FREELANCE_CLIENT
491     if ( cm_freelanceEnabled && 
492          scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
493          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
494          scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
495         StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
496         ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
497         code = 0;
498     } else 
499 #endif /* AFS_FREELANCE_CLIENT */
500     {
501         cellp = cm_FindCellByID(scp->fid.cell);
502         if (cellp) {
503             StringCbCopyA(ioctlp->outDatap, 999999, cellp->name);
504             ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
505             code = 0;
506         }
507         else 
508             code = CM_ERROR_NOSUCHCELL;
509     }
510
511     cm_ReleaseSCache(scp);
512     return code;
513 }
514
515 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
516 {
517     cm_conn_t *connp;
518     cm_scache_t *scp;
519     AFSOpaque acl;
520     AFSFetchStatus fileStatus;
521     AFSVolSync volSync;
522     long code;
523     AFSFid fid;
524     cm_req_t req;
525     struct rx_connection * callp;
526
527     cm_InitReq(&req);
528
529     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
530     if (code) return code;
531         
532     /* now make the get acl call */
533     fid.Volume = scp->fid.volume;
534     fid.Vnode = scp->fid.vnode;
535     fid.Unique = scp->fid.unique;
536     do {
537         acl.AFSOpaque_val = ioctlp->inDatap;
538         acl.AFSOpaque_len = strlen(ioctlp->inDatap)+1;
539         code = cm_Conn(&scp->fid, userp, &req, &connp);
540         if (code) continue;
541
542         callp = cm_GetRxConn(connp);
543         code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
544         rx_PutConnection(callp);
545
546     } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
547     code = cm_MapRPCError(code, &req);
548
549     /* invalidate cache info, since we just trashed the ACL cache */
550     lock_ObtainMutex(&scp->mx);
551     cm_DiscardSCache(scp);
552     lock_ReleaseMutex(&scp->mx);
553
554     cm_ReleaseSCache(scp);
555
556     return code;
557 }
558
559 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
560 {
561     long code;
562     cm_scache_t *scp;
563     unsigned long volume;
564     int i;
565     cm_req_t req;
566
567     cm_InitReq(&req);
568
569     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
570     if (code) return code;
571         
572     volume = scp->fid.volume;
573     cm_ReleaseSCache(scp);
574
575     lock_ObtainWrite(&cm_scacheLock);
576     for (i=0; i<cm_data.hashTableSize; i++) {
577         for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
578             if (scp->fid.volume == volume) {
579                 cm_HoldSCacheNoLock(scp);
580                 lock_ReleaseWrite(&cm_scacheLock);
581
582                 /* now flush the file */
583                 code = cm_FlushFile(scp, userp, &req);
584                 if ( code )
585                     afsi_log("cm_FlushFile returns error: [%x]",code);
586                 lock_ObtainWrite(&cm_scacheLock);
587                 cm_ReleaseSCacheNoLock(scp);
588             }
589         }
590     }
591     lock_ReleaseWrite(&cm_scacheLock);
592
593     return code;
594 }
595
596 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
597 {
598     long code;
599     cm_scache_t *scp;
600     cm_req_t req;
601
602     cm_InitReq(&req);
603
604     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
605     if (code) return code;
606         
607     cm_FlushFile(scp, userp, &req);
608     cm_ReleaseSCache(scp);
609
610     return 0;
611 }
612
613 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
614 {
615     cm_scache_t *scp;
616     char volName[32];
617     char offLineMsg[256];
618     char motd[256];
619     cm_conn_t *tcp;
620     long code;
621     AFSFetchVolumeStatus volStat;
622     AFSStoreVolumeStatus storeStat;
623     cm_volume_t *tvp;
624     char *cp;
625     cm_cell_t *cellp;
626     cm_req_t req;
627     struct rx_connection * callp;
628
629     cm_InitReq(&req);
630
631     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
632     if (code) return code;
633
634     cellp = cm_FindCellByID(scp->fid.cell);
635     osi_assert(cellp);
636
637     if (scp->flags & CM_SCACHEFLAG_RO) {
638         cm_ReleaseSCache(scp);
639         return CM_ERROR_READONLY;
640     }
641
642     code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, &tvp);
643     if (code) {
644         cm_ReleaseSCache(scp);
645         return code;
646     }
647
648     /* Copy the junk out, using cp as a roving pointer. */
649     cp = ioctlp->inDatap;
650     memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
651     cp += sizeof(AFSFetchVolumeStatus);
652     StringCbCopyA(volName, sizeof(volName), cp);
653     cp += strlen(volName)+1;
654     StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
655     cp +=  strlen(offLineMsg)+1;
656     StringCbCopyA(motd, sizeof(motd), cp);
657     storeStat.Mask = 0;
658     if (volStat.MinQuota != -1) {
659         storeStat.MinQuota = volStat.MinQuota;
660         storeStat.Mask |= AFS_SETMINQUOTA;
661     }
662     if (volStat.MaxQuota != -1) {
663         storeStat.MaxQuota = volStat.MaxQuota;
664         storeStat.Mask |= AFS_SETMAXQUOTA;
665     }
666
667     do {
668         code = cm_Conn(&scp->fid, userp, &req, &tcp);
669         if (code) continue;
670
671         callp = cm_GetRxConn(tcp);
672         code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
673                                       &storeStat, volName, offLineMsg, motd);
674         rx_PutConnection(callp);
675
676     } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
677     code = cm_MapRPCError(code, &req);
678
679     /* return on failure */
680     cm_ReleaseSCache(scp);
681     if (code) {
682         return code;
683     }
684
685     /* we are sending parms back to make compat. with prev system.  should
686      * change interface later to not ask for current status, just set
687      * new status
688      */
689     cp = ioctlp->outDatap;
690     memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
691     cp += sizeof(VolumeStatus);
692     StringCbCopyA(cp, 999999, volName);
693     cp += strlen(volName)+1;
694     StringCbCopyA(cp, 999999, offLineMsg);
695     cp += strlen(offLineMsg)+1;
696     StringCbCopyA(cp, 999999, motd);
697     cp += strlen(motd)+1;
698
699     /* now return updated return data pointer */
700     ioctlp->outDatap = cp;
701
702     return 0;
703 }       
704
705 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
706 {
707     char volName[32];
708     cm_scache_t *scp;
709     char offLineMsg[256];
710     char motd[256];
711     cm_conn_t *tcp;
712     register long code;
713     AFSFetchVolumeStatus volStat;
714     register char *cp;
715     char *Name;
716     char *OfflineMsg;
717     char *MOTD;
718     cm_req_t req;
719     struct rx_connection * callp;
720
721     cm_InitReq(&req);
722
723     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
724     if (code) return code;
725
726     Name = volName;
727     OfflineMsg = offLineMsg;
728     MOTD = motd;
729     do {
730         code = cm_Conn(&scp->fid, userp, &req, &tcp);
731         if (code) continue;
732
733         callp = cm_GetRxConn(tcp);
734         code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
735                                       &volStat, &Name, &OfflineMsg, &MOTD);
736         rx_PutConnection(callp);
737
738     } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
739     code = cm_MapRPCError(code, &req);
740
741     cm_ReleaseSCache(scp);
742     if (code) return code;
743
744     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
745     cp = ioctlp->outDatap;
746     memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
747     cp += sizeof(AFSFetchVolumeStatus);
748     StringCbCopyA(cp, 999999, volName);
749     cp += strlen(volName)+1;
750     StringCbCopyA(cp, 999999, offLineMsg);
751     cp += strlen(offLineMsg)+1;
752     StringCbCopyA(cp, 999999, motd);
753     cp += strlen(motd)+1;
754
755     /* return new size */
756     ioctlp->outDatap = cp;
757
758     return 0;
759 }
760
761 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
762 {
763     long code;
764     cm_scache_t *scp;
765     cm_cell_t *cellp;
766     cm_volume_t *tvp;
767     cm_serverRef_t **tsrpp, *current;
768     cm_server_t *tsp;
769     unsigned long volume;
770     char *cp;
771     cm_req_t req;
772
773     cm_InitReq(&req);
774
775     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
776     if (code) return code;
777         
778     volume = scp->fid.volume;
779
780     cellp = cm_FindCellByID(scp->fid.cell);
781     osi_assert(cellp);
782
783     cm_ReleaseSCache(scp);
784
785     code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
786     if (code) return code;
787         
788     cp = ioctlp->outDatap;
789         
790     lock_ObtainMutex(&tvp->mx);
791     tsrpp = cm_GetVolServers(tvp, volume);
792     lock_ObtainRead(&cm_serverLock);
793     for (current = *tsrpp; current; current = current->next) {
794         tsp = current->server;
795         memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
796         cp += sizeof(long);
797     }
798     lock_ReleaseRead(&cm_serverLock);
799     cm_FreeServerList(tsrpp);
800     lock_ReleaseMutex(&tvp->mx);
801
802     /* still room for terminating NULL, add it on */
803     volume = 0; /* reuse vbl */
804     memcpy(cp, (char *)&volume, sizeof(long));
805     cp += sizeof(long);
806
807     ioctlp->outDatap = cp;
808     cm_PutVolume(tvp);
809     return 0;
810 }       
811
812 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
813 {
814     long code;
815     cm_scache_t *dscp;
816     cm_scache_t *scp;
817     char *cp;
818     cm_req_t req;
819
820     cm_InitReq(&req);
821
822     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
823     if (code) return code;
824
825     cp = ioctlp->inDatap;
826
827     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
828     cm_ReleaseSCache(dscp);
829     if (code) return code;
830         
831     lock_ObtainMutex(&scp->mx);
832
833     /* now check that this is a real mount point */
834     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
835         lock_ReleaseMutex(&scp->mx);
836         cm_ReleaseSCache(scp);
837         return CM_ERROR_INVAL;
838     }
839
840     code = cm_ReadMountPoint(scp, userp, &req);
841     if (code == 0) {
842         cp = ioctlp->outDatap;
843         StringCbCopyA(cp, 999999, scp->mountPointStringp);
844         cp += strlen(cp) + 1;
845         ioctlp->outDatap = cp;
846     }
847     lock_ReleaseMutex(&scp->mx);
848     cm_ReleaseSCache(scp);
849
850     return code;
851 }       
852
853 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
854 {
855     long code;
856     cm_scache_t *dscp;
857     cm_scache_t *scp;
858     char *cp;
859     cm_req_t req;
860
861     cm_InitReq(&req);
862
863     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
864     if (code) return code;
865
866     cp = ioctlp->inDatap;
867
868     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
869         
870     /* if something went wrong, bail out now */
871     if (code) {
872         goto done;
873     }
874         
875     lock_ObtainMutex(&scp->mx);
876     code = cm_SyncOp(scp, NULL, userp, &req, 0,
877                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
878     if (code) {     
879         lock_ReleaseMutex(&scp->mx);
880         cm_ReleaseSCache(scp);
881         goto done;
882     }
883
884     /* now check that this is a real mount point */
885     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
886         lock_ReleaseMutex(&scp->mx);
887         cm_ReleaseSCache(scp);
888         code = CM_ERROR_INVAL;
889         goto done;
890     }
891
892     /* time to make the RPC, so drop the lock */
893     lock_ReleaseMutex(&scp->mx);
894     cm_ReleaseSCache(scp);
895
896     /* easier to do it this way */
897     code = cm_Unlink(dscp, cp, userp, &req);
898     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
899         smb_NotifyChange(FILE_ACTION_REMOVED,
900                           FILE_NOTIFY_CHANGE_DIR_NAME,
901                           dscp, cp, NULL, TRUE);
902
903   done:
904     cm_ReleaseSCache(dscp);
905     return code;
906 }
907
908 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
909 {
910     cm_cell_t *cellp;
911     chservinfo_t csi;
912     char *tp;
913     char *cp;
914     long temp;
915     cm_server_t *tsp;
916     int haveCell;
917         
918     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
919     tp = ioctlp->inDatap;
920     haveCell = 0;
921
922     memcpy(&temp, tp, sizeof(temp));
923     if (temp == 0x12345678) {   /* For afs3.3 version */
924         memcpy(&csi, tp, sizeof(csi));
925         if (csi.tinterval >= 0) {
926             cp = ioctlp->outDatap;
927             memcpy(cp, (char *)&cm_daemonCheckInterval, sizeof(long));
928             ioctlp->outDatap += sizeof(long);
929             if (csi.tinterval > 0) {
930                 if (!smb_SUser(userp))
931                     return CM_ERROR_NOACCESS;
932                 cm_daemonCheckInterval = csi.tinterval;
933             }
934             return 0;
935         }
936         if (csi.tsize)
937             haveCell = 1;
938         temp = csi.tflags;
939         cp = csi.tbuffer;
940     } else {    /* For pre afs3.3 versions */
941         memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
942         ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
943         if (cp - ioctlp->inAllocp < ioctlp->inCopied)   /* still more data available */
944             haveCell = 1;
945     }       
946
947     /* 
948      * 1: fast check, don't contact servers.
949      * 2: local cell only.
950      */
951     if (haveCell) {
952         /* have cell name, too */
953         cellp = cm_GetCell(cp, 0);
954         if (!cellp) return CM_ERROR_NOSUCHCELL;
955     }
956     else cellp = (cm_cell_t *) 0;
957     if (!cellp && (temp & 2)) {
958         /* use local cell */
959         cellp = cm_FindCellByID(1);
960     }
961     if (!(temp & 1)) {  /* if not fast, call server checker routine */
962         /* check down servers */
963         cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
964                          cellp);
965     }       
966
967     /* now return the current down server list */
968     cp = ioctlp->outDatap;
969     lock_ObtainRead(&cm_serverLock);
970     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
971         if (cellp && tsp->cellp != cellp) continue;     /* cell spec'd and wrong */
972         if ((tsp->flags & CM_SERVERFLAG_DOWN)
973              && tsp->type == CM_SERVER_FILE) {
974             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
975             cp += sizeof(long);
976         }
977     }
978     lock_ReleaseRead(&cm_serverLock);
979
980     ioctlp->outDatap = cp;
981     return 0;
982 }
983
984 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
985 {
986     /* we don't print anything superfluous, so we don't support the gag call */
987     return CM_ERROR_INVAL;
988 }
989
990 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
991 {
992     cm_CheckVolumes();
993     return 0;
994 }       
995
996 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
997 {
998     long temp;
999     long code;
1000
1001     cm_SkipIoctlPath(ioctlp);
1002
1003     memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1004     if (temp == 0) 
1005         temp = cm_data.buf_nOrigBuffers;
1006     else {
1007         /* temp is in 1K units, convert to # of buffers */
1008         temp = temp / (cm_data.buf_blockSize / 1024);
1009     }       
1010
1011     /* now adjust the cache size */
1012     code = buf_SetNBuffers(temp);
1013
1014     return code;
1015 }
1016
1017 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1018 {
1019     long inValue;
1020         
1021     cm_SkipIoctlPath(ioctlp);
1022         
1023     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1024
1025     /* print trace */
1026     if (inValue & 8) {
1027         afsd_ForceTrace(FALSE);
1028         buf_ForceTrace(FALSE);
1029     }
1030         
1031     if (inValue & 2) {
1032         /* set tracing value to low order bit */
1033         if ((inValue & 1) == 0) {
1034             /* disable tracing */
1035             osi_LogDisable(afsd_logp);
1036         }
1037         else {
1038             /* enable tracing */
1039             osi_LogEnable(afsd_logp);
1040         }
1041     }
1042
1043     /* see if we're supposed to do a reset, too */
1044     if (inValue & 4) {
1045         osi_LogReset(afsd_logp);
1046     }
1047
1048     /* and copy out tracing flag */
1049     inValue = afsd_logp->enabled;       /* use as a temp vbl */
1050     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1051     ioctlp->outDatap += sizeof(long);
1052     return 0;
1053 }       
1054
1055 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1056 {
1057     cm_cacheParms_t parms;
1058
1059     memset(&parms, 0, sizeof(parms));
1060
1061     /* first we get, in 1K units, the cache size */
1062     parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1063
1064     /* and then the actual # of buffers in use (not in the free list, I guess,
1065      * will be what we do).
1066      */
1067     parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1068
1069     memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1070     ioctlp->outDatap += sizeof(parms);
1071
1072     return 0;
1073 }
1074
1075 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1076 {
1077     long whichCell;
1078     long magic = 0;
1079     cm_cell_t *tcellp;
1080     cm_serverRef_t *serverRefp;
1081     cm_server_t *serverp;
1082     long i;
1083     char *cp;
1084     char *tp;
1085     char *basep;
1086
1087     cm_SkipIoctlPath(ioctlp);
1088
1089     tp = ioctlp->inDatap;
1090
1091     memcpy((char *)&whichCell, tp, sizeof(long));
1092     tp += sizeof(long);
1093
1094     /* see if more than one long passed in, ignoring the null pathname (the -1) */
1095     if (ioctlp->inCopied-1 > sizeof(long)) {
1096         memcpy((char *)&magic, tp, sizeof(long));
1097     }
1098
1099     lock_ObtainRead(&cm_cellLock);
1100     for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->nextp) {
1101         if (whichCell == 0) break;
1102         whichCell--;
1103     }
1104     lock_ReleaseRead(&cm_cellLock);
1105     if (tcellp) {
1106         int max = 8;
1107
1108         cp = ioctlp->outDatap;
1109
1110         if (magic == 0x12345678) {
1111             memcpy(cp, (char *)&magic, sizeof(long));
1112             max = 13;
1113         }
1114         memset(cp, 0, max * sizeof(long));
1115         basep = cp;
1116         lock_ObtainRead(&cm_serverLock);        /* for going down server list */
1117         /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1118         serverRefp = tcellp->vlServersp;
1119         for (i=0; i<max; i++) {
1120             if (!serverRefp) break;
1121             serverp = serverRefp->server;
1122             memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1123             cp += sizeof(long);
1124             serverRefp = serverRefp->next;
1125         }
1126         lock_ReleaseRead(&cm_serverLock);
1127         cp = basep + max * sizeof(afs_int32);
1128         StringCbCopyA(cp, 999999, tcellp->name);
1129         cp += strlen(tcellp->name)+1;
1130         ioctlp->outDatap = cp;
1131     }
1132
1133     if (tcellp) 
1134         return 0;
1135     else 
1136         return CM_ERROR_NOMORETOKENS;   /* mapped to EDOM */
1137 }
1138
1139 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1140
1141 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1142 {
1143     /* NT cache manager will read cell information from CellServDB each time
1144      * cell is accessed. So, this call is necessary only if list of server for a cell 
1145      * changes (or IP addresses of cell servers changes).
1146      * All that needs to be done is to refresh server information for all cells that 
1147      * are already loaded.
1148   
1149      * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1150      */  
1151   
1152     cm_cell_t *cp;
1153   
1154     cm_SkipIoctlPath(ioctlp);
1155     lock_ObtainWrite(&cm_cellLock);
1156   
1157     for (cp = cm_data.allCellsp; cp; cp=cp->nextp) 
1158     {
1159         long code;
1160         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1161         cm_FreeServerList(&cp->vlServersp);
1162         cp->vlServersp = NULL;
1163         code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1164 #ifdef AFS_AFSDB_ENV
1165         if (code) {
1166             if (cm_dnsEnabled) {
1167                 int ttl;
1168                 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1169                 if ( code == 0 ) { /* got cell from DNS */
1170                     cp->flags |= CM_CELLFLAG_DNS;
1171                     cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1172                     cp->timeout = time(0) + ttl;
1173                 }
1174             }
1175         } 
1176         else {
1177             cp->flags &= ~CM_CELLFLAG_DNS;
1178         }
1179 #endif /* AFS_AFSDB_ENV */
1180         if (code) {
1181             cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1182         }
1183         else {
1184             cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1185             cm_RandomizeServer(&cp->vlServersp);
1186         }
1187     }
1188     
1189     lock_ReleaseWrite(&cm_cellLock);
1190     return 0;       
1191 }
1192
1193 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1194 {
1195         long code = 0;
1196
1197         if (cm_freelanceEnabled) {
1198             if (cm_GetRootCellName(ioctlp->outDatap))
1199                 StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
1200             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1201         } else if (cm_data.rootCellp) {
1202             /* return the default cellname to the caller */
1203             StringCbCopyA(ioctlp->outDatap, 999999, cm_data.rootCellp->name);
1204             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1205         } else {
1206             /* if we don't know our default cell, return failure */
1207             code = CM_ERROR_NOSUCHCELL;
1208     }
1209
1210     return code;
1211 }
1212
1213 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1214 {
1215     long setSysName, foundname = 0;
1216     char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1217     int t, count, num = 0;
1218     char **sysnamelist[MAXSYSNAME];
1219         
1220     cm_SkipIoctlPath(ioctlp);
1221
1222     memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1223     ioctlp->inDatap += sizeof(long);
1224         
1225     if (setSysName) {
1226         /* check my args */
1227         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1228             return EINVAL;
1229         cp2 = ioctlp->inDatap;
1230         for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1231             /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1232             t = strlen(cp);
1233             if (t >= MAXSYSNAME || t <= 0)
1234                 return EINVAL;
1235             /* check for names that can shoot us in the foot */
1236             if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1237                 return EINVAL;
1238             cp += t + 1;
1239         }
1240         /* args ok */
1241
1242         /* inname gets first entry in case we're being a translator */
1243         /* (we are never a translator) */
1244         t = strlen(ioctlp->inDatap);
1245         memcpy(inname, ioctlp->inDatap, t + 1);
1246         ioctlp->inDatap += t + 1;
1247         num = count;
1248     }
1249
1250     /* Not xlating, so local case */
1251     if (!cm_sysName)
1252         osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1253
1254     if (!setSysName) {      /* user just wants the info */
1255         StringCbCopyA(outname, sizeof(outname), cm_sysName);
1256         foundname = cm_sysNameCount;
1257         *sysnamelist = cm_sysNameList;
1258     } else {        
1259         /* Local guy; only root can change sysname */
1260         /* clear @sys entries from the dnlc, once afs_lookup can
1261          * do lookups of @sys entries and thinks it can trust them */
1262         /* privs ok, store the entry, ... */
1263         StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1264         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1265         if (setSysName > 1) {       /* ... or list */
1266             cp = ioctlp->inDatap;
1267             for (count = 1; count < setSysName; ++count) {
1268                 if (!cm_sysNameList[count])
1269                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1270                                __FILE__, __LINE__);
1271                 t = strlen(cp);
1272                 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1273                 cp += t + 1;
1274             }
1275         }
1276         cm_sysNameCount = setSysName;
1277     }
1278
1279     if (!setSysName) {
1280         /* return the sysname to the caller */
1281         cp = ioctlp->outDatap;
1282         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1283         cp += sizeof(afs_int32);        /* skip found flag */
1284         if (foundname) {
1285             StringCbCopyA(cp, 999999, outname);
1286             cp += strlen(outname) + 1;  /* skip name and terminating null char */
1287             for ( count=1; count < foundname ; ++count) {   /* ... or list */
1288                 if ( !(*sysnamelist)[count] )
1289                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
1290                                __FILE__, __LINE__);
1291                 t = strlen((*sysnamelist)[count]);
1292                 if (t >= MAXSYSNAME)
1293                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
1294                                __FILE__, __LINE__);
1295                 StringCbCopyA(cp, 999999, (*sysnamelist)[count]);
1296                 cp += t + 1;
1297             }
1298         }
1299         ioctlp->outDatap = cp;
1300     }
1301         
1302     /* done: success */
1303     return 0;
1304 }
1305
1306 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1307 {
1308     long temp;
1309     cm_cell_t *cellp;
1310
1311     cm_SkipIoctlPath(ioctlp);
1312
1313     cellp = cm_GetCell(ioctlp->inDatap, 0);
1314     if (!cellp) 
1315         return CM_ERROR_NOSUCHCELL;
1316
1317     temp = 0;
1318     lock_ObtainMutex(&cellp->mx);
1319     if (cellp->flags & CM_CELLFLAG_SUID)
1320         temp |= CM_SETCELLFLAG_SUID;
1321     lock_ReleaseMutex(&cellp->mx);
1322         
1323     /* now copy out parm */
1324     memcpy(ioctlp->outDatap, &temp, sizeof(long));
1325     ioctlp->outDatap += sizeof(long);
1326
1327     return 0;
1328 }
1329
1330 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1331 {
1332     long temp;
1333     cm_cell_t *cellp;
1334
1335     cm_SkipIoctlPath(ioctlp);
1336
1337     cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1338     if (!cellp) 
1339         return CM_ERROR_NOSUCHCELL;
1340
1341     memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1342
1343     lock_ObtainMutex(&cellp->mx);
1344     if (temp & CM_SETCELLFLAG_SUID)
1345         cellp->flags |= CM_CELLFLAG_SUID;
1346     else
1347         cellp->flags &= ~CM_CELLFLAG_SUID;
1348     lock_ReleaseMutex(&cellp->mx);
1349
1350     return 0;
1351 }
1352
1353 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1354 {
1355     cm_SSetPref_t         *spin; /* input */
1356     cm_SPref_t        *srvin;   /* one input component */
1357     cm_server_t       *tsp;
1358     int                   i, vlonly, noServers, type;
1359     struct sockaddr_in  tmp;
1360     unsigned short        rank;
1361
1362     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1363
1364     spin           = (cm_SSetPref_t *)ioctlp->inDatap;
1365     noServers  = spin->num_servers;
1366     vlonly     = spin->flags;
1367     if ( vlonly )
1368         type = CM_SERVER_VLDB;
1369     else    
1370         type = CM_SERVER_FILE;
1371
1372     for ( i=0; i < noServers; i++) 
1373     {
1374         srvin          = &(spin->servers[i]);
1375         rank           = srvin->rank + (rand() & 0x000f);
1376         tmp.sin_addr   = srvin->host;
1377         tmp.sin_family = AF_INET;
1378
1379         tsp = cm_FindServer(&tmp, type);
1380         if ( tsp )              /* an existing server - ref count increased */
1381         {
1382             tsp->ipRank = rank; /* no need to protect by mutex*/
1383
1384             if (type == CM_SERVER_FILE)
1385             {   /* fileserver */
1386                 /* find volumes which might have RO copy 
1387                 /* on server and change the ordering of 
1388                  * their RO list 
1389                  */
1390                 cm_ChangeRankVolume(tsp);
1391             }
1392             else        
1393             {
1394                 /* set preferences for an existing vlserver */
1395                 cm_ChangeRankCellVLServer(tsp);
1396             }
1397             cm_PutServer(tsp);  /* decrease refcount */
1398         }
1399         else    /* add a new server without a cell */
1400         {
1401             tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
1402             tsp->ipRank = rank;
1403         }
1404     }
1405     return 0;
1406 }
1407
1408 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1409 {
1410     cm_SPrefRequest_t *spin; /* input */
1411     cm_SPrefInfo_t    *spout;   /* output */
1412     cm_SPref_t        *srvout;   /* one output component */
1413     cm_server_t       *tsp;
1414     int                   i, vlonly, noServers;
1415
1416     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1417
1418     spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
1419     spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
1420     srvout    = spout->servers;
1421     noServers = spin->num_servers; 
1422     vlonly    = spin->flags & CM_SPREF_VLONLY;
1423     spout->num_servers = 0;
1424
1425     lock_ObtainRead(&cm_serverLock); /* get server lock */
1426
1427     for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1428         if (spin->offset > i) {
1429             continue;    /* catch up to where we left off */
1430         }
1431
1432         if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1433             continue;   /* ignore fileserver for -vlserver option*/
1434         if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1435             continue;   /* ignore vlservers */
1436
1437         srvout->host = tsp->addr.sin_addr;
1438         srvout->rank = tsp->ipRank;
1439         srvout++;       
1440         spout->num_servers++;
1441         noServers--;
1442     }
1443     lock_ReleaseRead(&cm_serverLock); /* release server lock */
1444
1445     if ( tsp )  /* we ran out of space in the output buffer */
1446         spout->next_offset = i;
1447     else    
1448         spout->next_offset = 0; 
1449     ioctlp->outDatap += sizeof(cm_SPrefInfo_t) + 
1450         (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1451     return 0;
1452 }
1453
1454 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1455 {
1456     /* we ignore default asynchrony since we only have one way
1457      * of doing this today.
1458      */
1459     return 0;
1460 }       
1461
1462 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1463 {
1464     char leaf[LEAF_SIZE];
1465     long code;
1466     cm_scache_t *dscp;
1467     cm_attr_t tattr;
1468     char *cp;
1469     cm_req_t req;
1470     char mpInfo[256];
1471     char fullCell[256];
1472     char volume[256];
1473     char cell[256];
1474     int ttl;
1475
1476     cm_InitReq(&req);
1477         
1478     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1479     if (code) return code;
1480
1481     /* Translate chars for the mount point name */
1482     TranslateExtendedChars(leaf);
1483
1484     /* 
1485      * The fs command allows the user to specify partial cell names on NT.  These must
1486      * be expanded to the full cell name for mount points so that the mount points will
1487      * work on UNIX clients.
1488      */
1489
1490     /* Extract the possibly partial cell name */
1491     StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
1492         
1493     if (cp = strchr(cell, ':')) {
1494         /* Extract the volume name */
1495         *cp = 0;
1496         StringCbCopyA(volume,  sizeof(volume), cp + 1);
1497         
1498         /* Get the full name for this cell */
1499         code = cm_SearchCellFile(cell, fullCell, 0, 0);
1500 #ifdef AFS_AFSDB_ENV
1501         if (code && cm_dnsEnabled)
1502             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1503 #endif
1504         if (code)
1505             return CM_ERROR_NOSUCHCELL;
1506         
1507         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1508     } else {
1509         /* No cell name specified */
1510         StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1511     }
1512
1513 #ifdef AFS_FREELANCE_CLIENT
1514     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1515         /* we are adding the mount point to the root dir., so call
1516          * the freelance code to do the add. */
1517         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1518         code = cm_FreelanceAddMount(leaf, fullCell, volume, 
1519                                     *ioctlp->inDatap == '%', NULL);
1520         return code;
1521     }
1522 #endif
1523     /* create the symlink with mode 644.  The lack of X bits tells
1524      * us that it is a mount point.
1525      */
1526     tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1527     tattr.unixModeBits = 0644;
1528     tattr.clientModTime = time(NULL);
1529
1530     code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1531     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1532         smb_NotifyChange(FILE_ACTION_ADDED,
1533                          FILE_NOTIFY_CHANGE_DIR_NAME,
1534                          dscp, leaf, NULL, TRUE);
1535
1536     cm_ReleaseSCache(dscp);
1537     return code;
1538 }
1539
1540 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1541 {
1542     char leaf[LEAF_SIZE];
1543     long code;
1544     cm_scache_t *dscp;
1545     cm_attr_t tattr;
1546     char *cp;
1547     cm_req_t req;
1548
1549     cm_InitReq(&req);
1550
1551     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1552     if (code) return code;
1553
1554     /* Translate chars for the link name */
1555     TranslateExtendedChars(leaf);
1556
1557     /* Translate chars for the linked to name */
1558     TranslateExtendedChars(ioctlp->inDatap);
1559
1560     cp = ioctlp->inDatap;               /* contents of link */
1561
1562 #ifdef AFS_FREELANCE_CLIENT
1563     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1564         /* we are adding the symlink to the root dir., so call
1565          * the freelance code to do the add. */
1566         if (cp[0] == cp[1] && cp[1] == '\\' && 
1567             !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
1568         {
1569             /* skip \\AFS\ or \\AFS\all\ */
1570             char * p;
1571             p = cp + 2 + strlen(cm_NetbiosName) + 1;
1572             if ( !_strnicmp("all", p, 3) )
1573                 p += 4;
1574             cp = p;
1575         }
1576         osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1577         code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1578         return code;
1579     }
1580 #endif
1581
1582     /* Create symlink with mode 0755. */
1583     tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1584     tattr.unixModeBits = 0755;
1585
1586     code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1587     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1588         smb_NotifyChange(FILE_ACTION_ADDED,
1589                           FILE_NOTIFY_CHANGE_FILE_NAME
1590                           | FILE_NOTIFY_CHANGE_DIR_NAME,
1591                           dscp, leaf, NULL, TRUE);
1592
1593     cm_ReleaseSCache(dscp);
1594
1595     return code;
1596 }
1597
1598
1599 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1600 {
1601     long code;
1602     cm_scache_t *dscp;
1603     cm_scache_t *scp;
1604     char *cp;
1605     cm_space_t *spacep;
1606     cm_scache_t *newRootScp;
1607     cm_req_t req;
1608
1609     cm_InitReq(&req);
1610
1611     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1612     if (code) return code;
1613
1614     cp = ioctlp->inDatap;
1615
1616     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1617     cm_ReleaseSCache(dscp);
1618     if (code) return code;
1619
1620     /* Check that it's a real symlink */
1621     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1622         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1623         scp->fileType != CM_SCACHETYPE_INVALID) {
1624         cm_ReleaseSCache(scp);
1625         return CM_ERROR_INVAL;
1626     }
1627
1628     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1629     cm_ReleaseSCache(scp);
1630     if (code == 0) {
1631         cp = ioctlp->outDatap;
1632         if (newRootScp != NULL) {
1633             StringCbCopyA(cp, 999999, cm_mountRoot);
1634             StringCbCatA(cp, 999999, "/");
1635             cp += strlen(cp);
1636         }
1637         StringCbCopyA(cp, 999999, spacep->data);
1638         cp += strlen(cp) + 1;
1639         ioctlp->outDatap = cp;
1640         cm_FreeSpace(spacep);
1641         if (newRootScp != NULL)
1642             cm_ReleaseSCache(newRootScp);
1643         code = 0;
1644     } else if (code == CM_ERROR_PATH_NOT_COVERED && 
1645                 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1646                code == CM_ERROR_NOSUCHPATH &&
1647                 scp->fileType == CM_SCACHETYPE_INVALID) {
1648         cp = ioctlp->outDatap;
1649         StringCbCopyA(cp, 999999, spacep->data);
1650         cp += strlen(cp) + 1;
1651         ioctlp->outDatap = cp;
1652         cm_FreeSpace(spacep);
1653         if (newRootScp != NULL)
1654             cm_ReleaseSCache(newRootScp);
1655         code = 0;
1656     }
1657
1658     return code;
1659 }
1660
1661 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1662 {/*CHECK FOR VALID SYMLINK*/
1663     long code;
1664     cm_scache_t *dscp;
1665     cm_scache_t *scp;
1666     char *cp;
1667     cm_req_t req;
1668
1669     cm_InitReq(&req);
1670
1671     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1672     if (code) return code;
1673
1674     cp = ioctlp->inDatap;
1675     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1676
1677     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1678     cm_ReleaseSCache(dscp);
1679     if (code) return code;
1680
1681     /* Check that it's a real symlink */
1682     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1683         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1684         scp->fileType != CM_SCACHETYPE_INVALID)
1685         code = CM_ERROR_INVAL;
1686     cm_ReleaseSCache(scp);
1687     return code;
1688 }
1689
1690 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1691 {
1692     long code;
1693     cm_scache_t *dscp;
1694     cm_scache_t *scp;
1695     char *cp;
1696     cm_req_t req;
1697
1698     cm_InitReq(&req);
1699
1700     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1701     if (code) return code;
1702
1703     cp = ioctlp->inDatap;
1704
1705 #ifdef AFS_FREELANCE_CLIENT
1706     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1707         /* we are adding the mount point to the root dir., so call
1708          * the freelance code to do the add. */
1709         osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
1710         code = cm_FreelanceRemoveSymlink(cp);
1711         return code;
1712     }
1713 #endif
1714
1715     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1716         
1717     /* if something went wrong, bail out now */
1718     if (code) {
1719         goto done;
1720     }
1721         
1722     lock_ObtainMutex(&scp->mx);
1723     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1724                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1725     if (code) {     
1726         lock_ReleaseMutex(&scp->mx);
1727         cm_ReleaseSCache(scp);
1728         goto done;
1729     }
1730         
1731     /* now check that this is a real symlink */
1732     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1733         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1734         scp->fileType != CM_SCACHETYPE_INVALID) {
1735         lock_ReleaseMutex(&scp->mx);
1736         cm_ReleaseSCache(scp);
1737         code = CM_ERROR_INVAL;
1738         goto done;
1739     }
1740         
1741     /* time to make the RPC, so drop the lock */
1742     lock_ReleaseMutex(&scp->mx);
1743     cm_ReleaseSCache(scp);
1744         
1745     /* easier to do it this way */
1746     code = cm_Unlink(dscp, cp, userp, &req);
1747     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1748         smb_NotifyChange(FILE_ACTION_REMOVED,
1749                           FILE_NOTIFY_CHANGE_FILE_NAME
1750                           | FILE_NOTIFY_CHANGE_DIR_NAME,
1751                           dscp, cp, NULL, TRUE);
1752
1753   done:
1754     cm_ReleaseSCache(dscp);
1755     return code;
1756 }
1757
1758 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1759 {
1760     char *saveDataPtr;
1761     char *tp;
1762     int ticketLen;
1763     char *ticket;
1764     int ctSize;
1765     struct ClearToken ct;
1766     cm_cell_t *cellp;
1767     cm_ucell_t *ucellp;
1768     char *uname = NULL;
1769     afs_uuid_t uuid;
1770     int flags;
1771     char sessionKey[8];
1772     char *smbname;
1773
1774     saveDataPtr = ioctlp->inDatap;
1775
1776     cm_SkipIoctlPath(ioctlp);
1777
1778     tp = ioctlp->inDatap;
1779
1780     /* ticket length */
1781     memcpy(&ticketLen, tp, sizeof(ticketLen));
1782     tp += sizeof(ticketLen);
1783     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
1784         return CM_ERROR_INVAL;
1785
1786     /* remember ticket and skip over it for now */
1787     ticket = tp;
1788     tp += ticketLen;
1789
1790     /* clear token size */
1791     memcpy(&ctSize, tp, sizeof(ctSize));
1792     tp += sizeof(ctSize);
1793     if (ctSize != sizeof(struct ClearToken))
1794         return CM_ERROR_INVAL;
1795
1796     /* clear token */
1797     memcpy(&ct, tp, ctSize);
1798     tp += ctSize;
1799     if (ct.AuthHandle == -1)
1800         ct.AuthHandle = 999;    /* more rxvab compat stuff */
1801
1802     /* more stuff, if any */
1803     if (ioctlp->inCopied > tp - saveDataPtr) {
1804         /* flags:  logon flag */
1805         memcpy(&flags, tp, sizeof(int));
1806         tp += sizeof(int);
1807
1808         /* cell name */
1809         cellp = cm_GetCell(tp, CM_FLAG_CREATE);
1810         if (!cellp) return CM_ERROR_NOSUCHCELL;
1811         tp += strlen(tp) + 1;
1812
1813         /* user name */
1814         uname = tp;
1815         tp += strlen(tp) + 1;
1816
1817 #ifndef AFSIFS                  /* no SMB username, so we cannot log based on this */
1818         if (flags & PIOCTL_LOGON) {
1819             /* SMB user name with which to associate tokens */
1820             smbname = tp;
1821             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
1822                      osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
1823             fprintf(stderr, "SMB name = %s\n", smbname);
1824             tp += strlen(tp) + 1;
1825         } else {
1826             osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
1827                      osi_LogSaveString(smb_logp,uname));
1828         }
1829 #endif
1830
1831 #ifndef DJGPP   /* for win95, session key is back in pioctl */
1832                 /* uuid */
1833         memcpy(&uuid, tp, sizeof(uuid));
1834         if (!cm_FindTokenEvent(uuid, sessionKey))
1835             return CM_ERROR_INVAL;
1836 #endif /* !DJGPP */
1837     } else {
1838         cellp = cm_data.rootCellp;
1839         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
1840     }
1841
1842     if (flags & PIOCTL_LOGON) {
1843         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname);
1844     }
1845
1846     /* store the token */
1847     lock_ObtainMutex(&userp->mx);
1848     ucellp = cm_GetUCell(userp, cellp);
1849     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1850     ucellp->ticketLen = ticketLen;
1851     if (ucellp->ticketp)
1852         free(ucellp->ticketp);  /* Discard old token if any */
1853     ucellp->ticketp = malloc(ticketLen);
1854     memcpy(ucellp->ticketp, ticket, ticketLen);
1855 #ifndef DJGPP
1856     /*
1857      * Get the session key from the RPC, rather than from the pioctl.
1858      */
1859     /*
1860     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1861     */
1862     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1863 #else
1864     /* for win95, we are getting the session key from the pioctl */
1865     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1866 #endif /* !DJGPP */
1867     ucellp->kvno = ct.AuthHandle;
1868     ucellp->expirationTime = ct.EndTimestamp;
1869     ucellp->gen++;
1870     if (uname) 
1871         StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
1872     ucellp->flags |= CM_UCELLFLAG_RXKAD;
1873     lock_ReleaseMutex(&userp->mx);
1874
1875     if (flags & PIOCTL_LOGON) {
1876         ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
1877     }
1878
1879     cm_ResetACLCache(userp);
1880
1881     return 0;
1882 }
1883
1884 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
1885 {
1886     char *tp, *cp;
1887     int iterator;
1888     int temp;
1889     cm_ucell_t *ucellp;
1890     struct ClearToken ct;
1891
1892     cm_SkipIoctlPath(ioctlp);
1893
1894     tp = ioctlp->inDatap;
1895     cp = ioctlp->outDatap;
1896
1897     /* iterator */
1898     memcpy(&iterator, tp, sizeof(iterator));
1899     tp += sizeof(iterator);
1900
1901     lock_ObtainMutex(&userp->mx);
1902
1903     /* look for token */
1904     for (;;iterator++) {
1905         ucellp = cm_FindUCell(userp, iterator);
1906         if (!ucellp) {
1907             lock_ReleaseMutex(&userp->mx);
1908             return CM_ERROR_NOMORETOKENS;
1909         }
1910         if (ucellp->flags & CM_UCELLFLAG_RXKAD)
1911             break;
1912     }       
1913
1914     /* new iterator */
1915     temp = ucellp->iterator + 1;
1916     memcpy(cp, &temp, sizeof(temp));
1917     cp += sizeof(temp);
1918
1919     /* ticket length */
1920     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
1921     cp += sizeof(ucellp->ticketLen);
1922
1923     /* ticket */
1924     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
1925     cp += ucellp->ticketLen;
1926
1927     /* clear token size */
1928     temp = sizeof(ct);
1929     memcpy(cp, &temp, sizeof(temp));
1930     cp += sizeof(temp);
1931
1932     /* clear token */
1933     ct.AuthHandle = ucellp->kvno;
1934 #ifndef DJGPP
1935     /*
1936      * Don't give out a real session key here
1937      */
1938     /*
1939     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1940     */
1941     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
1942 #else
1943     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1944 #endif /* !DJGPP */
1945     ct.ViceId = 37;                     /* XXX */
1946     ct.BeginTimestamp = 0;              /* XXX */
1947     ct.EndTimestamp = ucellp->expirationTime;
1948     memcpy(cp, &ct, sizeof(ct));
1949     cp += sizeof(ct);
1950
1951     /* Primary flag (unused) */
1952     temp = 0;
1953     memcpy(cp, &temp, sizeof(temp));
1954     cp += sizeof(temp);
1955
1956     /* cell name */
1957     StringCbCopyA(cp, 999999, ucellp->cellp->name);
1958     cp += strlen(cp) + 1;
1959
1960     /* user name */
1961     StringCbCopyA(cp, 999999, ucellp->userName);
1962     cp += strlen(cp) + 1;
1963
1964     ioctlp->outDatap = cp;
1965
1966     lock_ReleaseMutex(&userp->mx);
1967
1968     return 0;
1969 }
1970
1971 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1972 {
1973     char *cp;
1974     int temp;
1975     cm_cell_t *cellp;
1976     cm_ucell_t *ucellp;
1977     struct ClearToken ct;
1978     char *tp;
1979 #ifndef DJGPP
1980     afs_uuid_t uuid;
1981 #endif /* !DJGPP */
1982
1983     cm_SkipIoctlPath(ioctlp);
1984
1985     tp = ioctlp->inDatap;
1986
1987     cp = ioctlp->outDatap;
1988
1989     /* cell name is right here */
1990     cellp = cm_GetCell(tp, 0);
1991     if (!cellp) 
1992         return CM_ERROR_NOSUCHCELL;
1993     tp += strlen(tp) + 1;
1994
1995 #ifndef DJGPP
1996     /* uuid */
1997     memcpy(&uuid, tp, sizeof(uuid));
1998 #endif /* !DJGPP */
1999
2000     lock_ObtainMutex(&userp->mx);
2001
2002     ucellp = cm_GetUCell(userp, cellp);
2003     if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2004         lock_ReleaseMutex(&userp->mx);
2005         return CM_ERROR_NOMORETOKENS;
2006     }
2007
2008     /* ticket length */
2009     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2010     cp += sizeof(ucellp->ticketLen);
2011
2012     /* ticket */
2013     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2014     cp += ucellp->ticketLen;
2015
2016     /* clear token size */
2017     temp = sizeof(ct);
2018     memcpy(cp, &temp, sizeof(temp));
2019     cp += sizeof(temp);
2020
2021     /* clear token */
2022     ct.AuthHandle = ucellp->kvno;
2023 #ifndef DJGPP
2024     /*
2025      * Don't give out a real session key here
2026      */
2027     /*
2028     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2029     */
2030     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2031 #else
2032     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2033 #endif /* !DJGPP */
2034     ct.ViceId = 37;                     /* XXX */
2035     ct.BeginTimestamp = 0;              /* XXX */
2036     ct.EndTimestamp = ucellp->expirationTime;
2037     memcpy(cp, &ct, sizeof(ct));
2038     cp += sizeof(ct);
2039
2040     /* Primary flag (unused) */
2041     temp = 0;
2042     memcpy(cp, &temp, sizeof(temp));
2043     cp += sizeof(temp);
2044
2045     /* cell name */
2046     StringCbCopyA(cp, 999999, ucellp->cellp->name);
2047     cp += strlen(cp) + 1;
2048
2049     /* user name */
2050     StringCbCopyA(cp, 999999, ucellp->userName);
2051     cp += strlen(cp) + 1;
2052
2053     ioctlp->outDatap = cp;
2054
2055     lock_ReleaseMutex(&userp->mx);
2056
2057 #ifndef DJGPP
2058     cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2059 #endif /* !DJGPP */
2060
2061     return 0;
2062 }
2063
2064 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2065 {
2066     char *cp;
2067     cm_cell_t *cellp;
2068     cm_ucell_t *ucellp;
2069
2070     cm_SkipIoctlPath(ioctlp);
2071
2072     cp = ioctlp->outDatap;
2073
2074     /* cell name is right here */
2075     cellp = cm_GetCell(ioctlp->inDatap, 0);
2076     if (!cellp) return CM_ERROR_NOSUCHCELL;
2077
2078     lock_ObtainMutex(&userp->mx);
2079
2080     ucellp = cm_GetUCell(userp, cellp);
2081     if (!ucellp) {
2082         lock_ReleaseMutex(&userp->mx);
2083         return CM_ERROR_NOMORETOKENS;
2084     }
2085
2086     osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2087
2088     if (ucellp->ticketp) {
2089         free(ucellp->ticketp);
2090         ucellp->ticketp = NULL;
2091     }
2092     ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2093     ucellp->gen++;
2094
2095     lock_ReleaseMutex(&userp->mx);
2096
2097     cm_ResetACLCache(userp);
2098
2099     return 0;
2100 }
2101
2102 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2103 {
2104     cm_ucell_t *ucellp;
2105
2106     lock_ObtainMutex(&userp->mx);
2107
2108     for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2109         osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2110         ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2111         ucellp->gen++;
2112     }
2113
2114     lock_ReleaseMutex(&userp->mx);
2115
2116     cm_ResetACLCache(userp);
2117
2118     return 0;
2119 }
2120
2121 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2122 {
2123     char afspath[MAX_PATH];
2124     char *submountreqp;
2125     int nextAutoSubmount;
2126     HKEY hkSubmounts;
2127     DWORD dwType, dwSize;
2128     DWORD status;
2129     DWORD dwIndex;
2130     DWORD dwSubmounts;
2131
2132     cm_SkipIoctlPath(ioctlp);
2133
2134     /* Serialize this one, to prevent simultaneous mods
2135      * to afsdsbmt.ini
2136      */
2137     lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2138
2139     /* Parse the input parameters--first the required afs path,
2140      * then the requested submount name (which may be "").
2141      */
2142     cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2143     submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2144
2145     /* If the caller supplied a suggested submount name, see if
2146      * that submount name is in use... if so, the submount's path
2147      * has to match our path.
2148      */
2149
2150     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
2151                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2152                     0, 
2153                     "AFS", 
2154                     REG_OPTION_NON_VOLATILE,
2155                     KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2156                     NULL, 
2157                     &hkSubmounts,
2158                     NULL );
2159
2160     if (submountreqp && *submountreqp) {
2161         char submountPathNormalized[MAX_PATH];
2162         char submountPath[MAX_PATH];
2163
2164         dwSize = sizeof(submountPath);
2165         status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2166                                   &dwType, submountPath, &dwSize);
2167
2168         if (status != ERROR_SUCCESS) {
2169
2170             /* The suggested submount name isn't in use now--
2171              * so we can safely map the requested submount name
2172              * to the supplied path. Remember not to write the
2173              * leading "/afs" when writing out the submount.
2174              */
2175             RegSetValueEx( hkSubmounts, submountreqp, 0,
2176                            REG_EXPAND_SZ, 
2177                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2178                            &afspath[strlen(cm_mountRoot)]:"/",
2179                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2180                            strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2181
2182             RegCloseKey( hkSubmounts );
2183             StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2184             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2185             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2186             return 0;
2187         }
2188
2189         /* The suggested submount name is already in use--if the
2190          * supplied path matches the submount's path, we can still
2191          * use the suggested submount name.
2192          */
2193         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2194         if (!strcmp (submountPathNormalized, afspath)) {
2195             StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2196             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2197             RegCloseKey( hkSubmounts );
2198             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2199             return 0;
2200         }
2201     }
2202
2203     RegQueryInfoKey( hkSubmounts,
2204                      NULL,  /* lpClass */
2205                      NULL,  /* lpcClass */
2206                      NULL,  /* lpReserved */
2207                      NULL,  /* lpcSubKeys */
2208                      NULL,  /* lpcMaxSubKeyLen */
2209                      NULL,  /* lpcMaxClassLen */
2210                      &dwSubmounts, /* lpcValues */
2211                      NULL,  /* lpcMaxValueNameLen */
2212                      NULL,  /* lpcMaxValueLen */
2213                      NULL,  /* lpcbSecurityDescriptor */
2214                      NULL   /* lpftLastWriteTime */
2215                      );
2216
2217
2218     /* Having obtained a list of all available submounts, start
2219      * searching that list for a path which matches the requested
2220      * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2221      * submount, in case we need to add a new one later.
2222      */
2223
2224     nextAutoSubmount = 1;
2225
2226     for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2227         char submountPathNormalized[MAX_PATH];
2228         char submountPath[MAX_PATH] = "";
2229         DWORD submountPathLen = sizeof(submountPath);
2230         char submountName[MAX_PATH];
2231         DWORD submountNameLen = sizeof(submountName);
2232
2233         dwType = 0;
2234         RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2235                       &dwType, submountPath, &submountPathLen);
2236         if (dwType == REG_EXPAND_SZ) {
2237             char buf[MAX_PATH];
2238             StringCbCopyA(buf, MAX_PATH, submountPath);
2239             submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2240             if (submountPathLen > MAX_PATH)
2241                 continue;
2242         }
2243
2244         /* If this is an Auto### submount, remember its ### value */
2245         if ((!strnicmp (submountName, "auto", 4)) &&
2246              (isdigit (submountName[strlen("auto")]))) {
2247             int thisAutoSubmount;
2248             thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2249             nextAutoSubmount = max (nextAutoSubmount,
2250                                      thisAutoSubmount+1);
2251         }       
2252
2253         if ((submountPathLen == 0) ||
2254              (submountPathLen == sizeof(submountPath) - 1)) {
2255             continue;
2256         }
2257
2258         /* See if the path for this submount matches the path
2259          * that our caller specified. If so, we can return
2260          * this submount.
2261          */
2262         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2263         if (!strcmp (submountPathNormalized, afspath)) {
2264             StringCbCopyA(ioctlp->outDatap, 999999, submountName);
2265             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2266             RegCloseKey(hkSubmounts);
2267             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2268             return 0;
2269
2270         }
2271     }
2272
2273     /* We've been through the entire list of existing submounts, and
2274      * didn't find any which matched the specified path. So, we'll
2275      * just have to add one. Remember not to write the leading "/afs"
2276      * when writing out the submount.
2277      */
2278
2279     StringCbPrintfA(ioctlp->outDatap, 999999, "auto%ld", nextAutoSubmount);
2280
2281     RegSetValueEx( hkSubmounts, 
2282                    ioctlp->outDatap,
2283                    0,
2284                    REG_EXPAND_SZ, 
2285                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2286                    &afspath[strlen(cm_mountRoot)]:"/",
2287                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2288                    strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2289
2290     ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2291     RegCloseKey(hkSubmounts);
2292     lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2293     return 0;
2294 }
2295
2296 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2297 {
2298     memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2299     ioctlp->outDatap += sizeof(cryptall);
2300
2301     return 0;
2302 }
2303
2304 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2305 {
2306     cm_SkipIoctlPath(ioctlp);
2307
2308     memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2309
2310     return 0;
2311 }
2312
2313 #ifdef DJGPP
2314 extern int afsd_shutdown(int);
2315 extern int afs_shutdown;
2316
2317 long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
2318   afs_shutdown = 1;   /* flag to shut down */
2319   return 0;
2320 }
2321 #endif /* DJGPP */
2322
2323 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
2324 {
2325   smb_user_t *uidp = ioctlp->uidp;
2326
2327   if (uidp && uidp->unp) {
2328     memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
2329     ioctlp->outDatap += strlen(uidp->unp->name);
2330   }
2331
2332   return 0;
2333 }
2334
2335 /* 
2336  * functions to dump contents of various structures. 
2337  * In debug build (linked with crt debug library) will dump allocated but not freed memory
2338  */
2339 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
2340 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
2341 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
2342
2343 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
2344 {
2345     long inValue = 0;
2346     HANDLE hLogFile;
2347     char logfileName[MAX_PATH+1];
2348     char *cookie;
2349     DWORD dwSize;
2350   
2351 #ifdef _DEBUG  
2352     static _CrtMemState memstate;
2353 #endif
2354   
2355     cm_SkipIoctlPath(ioctlp);
2356     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
2357   
2358     dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
2359     if ( dwSize == 0 || dwSize > sizeof(logfileName) )
2360     {
2361         GetWindowsDirectory(logfileName, sizeof(logfileName));
2362     }
2363     strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
2364
2365     hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2366   
2367     if (!hLogFile)
2368     {
2369       /* error */
2370       inValue = -1;
2371       memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2372       ioctlp->outDatap += sizeof(long);
2373       
2374       return 0;               
2375     }
2376   
2377     SetFilePointer(hLogFile, 0, NULL, FILE_END);
2378   
2379     cookie = inValue ? "b" : "e";
2380   
2381 #ifdef _DEBUG  
2382   
2383     if (inValue)
2384     {
2385       _CrtMemCheckpoint(&memstate);           
2386     }
2387     else
2388     {
2389         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2390         _CrtSetReportFile(_CRT_WARN, hLogFile);
2391         _CrtMemDumpAllObjectsSince(&memstate);
2392     }
2393 #endif
2394   
2395     /* dump all interesting data */
2396     cm_DumpSCache(hLogFile, cookie, 1);
2397     cm_DumpBufHashTable(hLogFile, cookie, 1);
2398     smb_DumpVCP(hLogFile, cookie, 1);
2399
2400     CloseHandle(hLogFile);                          
2401   
2402     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2403     ioctlp->outDatap += sizeof(long);
2404   
2405     return 0;
2406 }