windows-unicode-support-20080509
[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 #include <afs/cellconfig.h>
13 #include <afs/ptserver.h>
14 #include <ubik.h>
15
16 #include <windows.h>
17 #include <errno.h>
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 #include "afsd_init.h"
28 #include <WINNT\afsreg.h>
29
30 #include "smb.h"
31
32 #include <rx/rxkad.h>
33 #include "afsrpc.h"
34
35 #include "cm_rpc.h"
36 #include <strsafe.h>
37 #include <winioctl.h>
38 #include <rx\rx.h>
39
40 #ifdef _DEBUG
41 #include <crtdbg.h>
42 #endif
43
44 /* Copied from afs_tokens.h */
45 #define PIOCTL_LOGON    0x1
46 #define MAX_PATH 260
47
48 static const char utf8_prefix[] = UTF8_PREFIX;
49 static const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
50
51 osi_mutex_t cm_Afsdsbmt_Lock;
52
53 extern afs_int32 cryptall;
54 extern char cm_NetbiosName[];
55
56 extern void afsi_log(char *pattern, ...);
57
58 void cm_InitIoctl(void)
59 {
60     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
61 }
62
63 long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
64 {
65     long code;
66
67     code = buf_CleanVnode(scp, userp, reqp);
68         
69     lock_ObtainWrite(&scp->rw);
70     cm_DiscardSCache(scp);
71     lock_ReleaseWrite(&scp->rw);
72
73     osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
74     return code;
75 }
76
77 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
78 {
79     long code;
80
81 #ifdef AFS_FREELANCE_CLIENT
82     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
83         cm_noteLocalMountPointChange();
84         return 0;
85     }
86 #endif
87
88     code = buf_FlushCleanPages(scp, userp, reqp);
89         
90     lock_ObtainWrite(&scp->rw);
91     cm_DiscardSCache(scp);
92
93     lock_ReleaseWrite(&scp->rw);
94
95     osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
96     return code;
97 }
98
99 long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
100 {
101     long code = 0;
102     cm_scache_t * pscp;
103   
104     pscp = cm_FindSCacheParent(scp);
105   
106     /* now flush the file */
107     code = cm_FlushFile(pscp, userp, reqp);
108     cm_ReleaseSCache(pscp);
109
110     return code;
111 }
112
113
114 long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
115 {
116     long code = 0;
117     cm_scache_t *scp;
118     int i;
119
120 #ifdef AFS_FREELANCE_CLIENT
121     if ( cell == AFS_FAKE_ROOT_CELL_ID && volume == AFS_FAKE_ROOT_VOL_ID ) {
122         cm_noteLocalMountPointChange();
123         return 0;
124     }
125 #endif
126
127     lock_ObtainWrite(&cm_scacheLock);
128     for (i=0; i<cm_data.scacheHashTableSize; i++) {
129         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
130             if (scp->fid.volume == volume && scp->fid.cell == cell) {
131                 cm_HoldSCacheNoLock(scp);
132                 lock_ReleaseWrite(&cm_scacheLock);
133
134                 /* now flush the file */
135                 code = cm_FlushFile(scp, userp, reqp);
136                 lock_ObtainWrite(&cm_scacheLock);
137                 cm_ReleaseSCacheNoLock(scp);
138             }
139         }
140     }
141     lock_ReleaseWrite(&cm_scacheLock);
142
143     return code;
144 }
145
146 /*
147  * cm_ResetACLCache -- invalidate ACL info for a user that has just
148  *                      obtained or lost tokens
149  */
150 void cm_ResetACLCache(cm_user_t *userp)
151 {
152     cm_scache_t *scp;
153     int hash;
154
155     lock_ObtainWrite(&cm_scacheLock);
156     for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
157         for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
158             cm_HoldSCacheNoLock(scp);
159             lock_ReleaseWrite(&cm_scacheLock);
160             lock_ObtainWrite(&scp->rw);
161             cm_InvalidateACLUser(scp, userp);
162             lock_ReleaseWrite(&scp->rw);
163             lock_ObtainWrite(&cm_scacheLock);
164             cm_ReleaseSCacheNoLock(scp);
165         }
166     }
167     lock_ReleaseWrite(&cm_scacheLock);
168 }       
169
170 /*
171  *  TranslateExtendedChars - This is a fix for TR 54482.
172  *
173  *  If an extended character (80 - FF) is entered into a file
174  *  or directory name in Windows, the character is translated
175  *  into the OEM character map before being passed to us.  Why
176  *  this occurs is unknown.  Our pioctl functions must match
177  *  this translation for paths given via our own commands (like
178  *  fs).  If we do not do this, then we will try to perform an
179  *  operation on a non-translated path, which we will fail to 
180  *  find, since the path was created with the translated chars.
181  *  This function performs the required translation.
182  */
183 void TranslateExtendedChars(char *str)
184 {
185     if (!str || !*str)
186         return;
187
188     CharToOem(str, str);
189 }
190         
191 /* parse the passed-in file name and do a namei on it.  If we fail,
192  * return an error code, otherwise return the vnode located in *scpp.
193  */
194 #define CM_PARSE_FLAG_LITERAL 1
195
196 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
197         cm_scache_t **scpp, afs_uint32 flags)
198 {
199     long code;
200     cm_scache_t *substRootp = NULL;
201     cm_scache_t *iscp = NULL;
202     char * relativePath;
203     char * lastComponent = NULL;
204     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
205     int free_path = FALSE;
206
207     relativePath = ioctlp->inDatap;
208     /* setup the next data value for the caller to use */
209     ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
210
211     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
212
213     /* This is usually the file name, but for StatMountPoint it is the path. */
214     /* ioctlp->inDatap can be either of the form:
215      *    \path\.
216      *    \path\file
217      *    \\netbios-name\submount\path\.
218      *    \\netbios-name\submount\path\file
219      */
220
221         /* We do not perform path name translation on the ioctl path data 
222          * because these paths were not translated by Windows through the
223          * file system API.  Therefore, they are not OEM characters but 
224          * whatever the display character set is.
225          */
226
227     // TranslateExtendedChars(relativePath);
228
229     /* This is usually nothing, but for StatMountPoint it is the file name. */
230     // TranslateExtendedChars(ioctlp->inDatap);
231
232     /* If the string starts with our UTF-8 prefix (which is the
233        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
234        strings), we assume that the provided path is UTF-8.  Otherwise
235        we have to convert the string to UTF-8, since that is what we
236        want to use everywhere else.*/
237
238     if (memcmp(relativePath, utf8_prefix, utf8_prefix_size) == 0) {
239         int len, normalized_len;
240         char * normalized_path;
241
242         /* String is UTF-8 */
243         relativePath += utf8_prefix_size;
244         ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
245
246         len = (ioctlp->inDatap - relativePath);
247
248         normalized_len = cm_NormalizeUtf8String(relativePath, len, NULL, 0);
249
250         if (normalized_len > len) {
251             normalized_path = malloc(normalized_len);
252             free_path = TRUE;
253         } else {
254             normalized_path = relativePath;
255         }
256
257         cm_NormalizeUtf8String(relativePath, len, normalized_path, normalized_len);
258
259         if (normalized_path != relativePath)
260             relativePath = normalized_path;
261     } else {
262         /* Not a UTF-8 string */
263         /* TODO: If this is an OEM string, we should convert it to
264            UTF-8. */
265     }
266
267     if (relativePath[0] == relativePath[1] &&
268          relativePath[1] == '\\' && 
269          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
270     {
271         char shareName[256];
272         char *sharePath;
273         int shareFound, i;
274
275         /* We may have found a UNC path. 
276          * If the first component is the NetbiosName,
277          * then throw out the second component (the submount)
278          * since it had better expand into the value of ioctl->tidPathp
279          */
280         char * p;
281         p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                      /* buffer overflow vuln.? */
282         if ( !_strnicmp("all", p, 3) )
283             p += 4;
284
285         for (i = 0; *p && *p != '\\'; i++,p++ ) {
286             shareName[i] = *p;
287         }
288         p++;                    /* skip past trailing slash */
289         shareName[i] = 0;       /* terminate string */
290
291         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
292         if ( shareFound ) {
293             /* we found a sharename, therefore use the resulting path */
294             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
295                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
296                              userp, sharePath, reqp, &substRootp);
297             free(sharePath);
298             if (code) {
299                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
300                 if (free_path)
301                     free(relativePath);
302                 return code;
303             }
304
305             lastComponent = strrchr(p, '\\');
306             if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
307                 *lastComponent = '\0';
308                 lastComponent++;
309
310                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
311                                  userp, NULL, reqp, &iscp);
312                 if (code == 0)
313                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
314                                     userp, NULL, reqp, scpp);
315                 if (iscp)
316                     cm_ReleaseSCache(iscp);
317             } else {
318                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
319                                 userp, NULL, reqp, scpp);
320             }
321             cm_ReleaseSCache(substRootp);
322             if (code) {
323                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
324                 if (free_path)
325                     free(relativePath);
326                 return code;
327             }
328         } else {
329             /* otherwise, treat the name as a cellname mounted off the afs root.
330              * This requires that we reconstruct the shareName string with 
331              * leading and trailing slashes.
332              */
333             p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
334             if ( !_strnicmp("all", p, 3) )
335                 p += 4;
336
337             shareName[0] = '/';
338             for (i = 1; *p && *p != '\\'; i++,p++ ) {
339                 shareName[i] = *p;
340             }
341             p++;                    /* skip past trailing slash */
342             shareName[i++] = '/';       /* add trailing slash */
343             shareName[i] = 0;       /* terminate string */
344
345
346             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
347                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
348                              userp, shareName, reqp, &substRootp);
349             if (code) {
350                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
351                 if (free_path)
352                     free(relativePath);
353                 return code;
354             }
355
356             lastComponent = strrchr(p, '\\');
357             if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
358                 *lastComponent = '\0';
359                 lastComponent++;
360
361                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
362                                  userp, NULL, reqp, &iscp);
363                 if (code == 0)
364                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
365                                     userp, NULL, reqp, scpp);
366                 if (iscp)
367                     cm_ReleaseSCache(iscp);
368             } else {
369                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
370                                 userp, NULL, reqp, scpp);
371             }
372
373             if (code) {
374                 cm_ReleaseSCache(substRootp);
375                 osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
376                 if (free_path)
377                     free(relativePath);
378                 return code;
379             }
380         }
381     } else {
382         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
383                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
384                          userp, ioctlp->tidPathp, reqp, &substRootp);
385         if (code) {
386             osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
387             if (free_path)
388                 free(relativePath);
389             return code;
390         }
391         
392         lastComponent = strrchr(relativePath, '\\');
393         if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
394             *lastComponent = '\0';
395             lastComponent++;
396
397             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
398                              userp, NULL, reqp, &iscp);
399             if (code == 0)
400                 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
401                                  userp, NULL, reqp, scpp);
402             if (iscp)
403                 cm_ReleaseSCache(iscp);
404         } else {
405             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
406                              userp, NULL, reqp, scpp);
407         }
408         if (code) {
409             cm_ReleaseSCache(substRootp);
410             osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
411             if (free_path)
412                 free(relativePath);
413             return code;
414         }
415     }
416
417     if (substRootp)
418         cm_ReleaseSCache(substRootp);
419
420     /* and return success */
421     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
422
423     if (free_path)
424         free(relativePath);
425     return 0;
426 }
427
428 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
429 {
430     size_t temp;
431         
432     temp = strlen(ioctlp->inDatap) + 1;
433     ioctlp->inDatap += temp;
434 }       
435
436 /* 
437  * Must be called before cm_ParseIoctlPath or cm_SkipIoctlPath 
438  */
439 static cm_ioctlQueryOptions_t * 
440 cm_IoctlGetQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
441 {
442     afs_uint32 pathlen = strlen(ioctlp->inDatap) + 1;
443     char *p = ioctlp->inDatap + pathlen;
444     cm_ioctlQueryOptions_t * optionsp = NULL;
445
446     if (ioctlp->inCopied > p - ioctlp->inAllocp) {
447         optionsp = (cm_ioctlQueryOptions_t *)p;
448         if (optionsp->size < 12 /* minimum size of struct */)
449             optionsp = NULL;
450     }
451
452     return optionsp;
453 }
454
455 /* 
456  * Must be called after cm_ParseIoctlPath or cm_SkipIoctlPath
457  * or any other time that ioctlp->inDatap points at the 
458  * cm_ioctlQueryOptions_t object.
459  */
460 static void
461 cm_IoctlSkipQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
462 {
463     cm_ioctlQueryOptions_t * optionsp = (cm_ioctlQueryOptions_t *)ioctlp->inDatap;
464     ioctlp->inDatap += optionsp->size;
465 }
466
467 /* format the specified path to look like "/afs/<cellname>/usr", by
468  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
469  * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
470  * intentionally returned as "/afs/"--this makes submount manipulation
471  * easier (because we can always jump past the initial "/afs" to find
472  * the AFS path that should be written into afsdsbmt.ini).
473  */
474 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
475 {
476     char *cp;
477     char bslash_mountRoot[256];
478        
479     strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
480     bslash_mountRoot[0] = '\\';
481        
482     if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
483         StringCbCopy(outpathp, outlen, inpathp);
484     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
485         StringCbCopy(outpathp, outlen, inpathp);
486     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
487         StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
488     else // inpathp looks like "<cell>/usr"
489         StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
490
491     for (cp = outpathp; *cp != 0; ++cp) {
492         if (*cp == '\\')
493             *cp = '/';
494     }       
495
496     if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
497         outpathp[strlen(outpathp)-1] = 0;
498     }
499
500     if (!strcmpi (outpathp, cm_mountRoot)) {
501         StringCbCopy(outpathp, outlen, cm_mountRoot);
502     }
503 }
504
505 #define LEAF_SIZE 256
506 /* parse the passed-in file name and do a namei on its parent.  If we fail,
507  * return an error code, otherwise return the vnode located in *scpp.
508  */
509 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
510                          cm_scache_t **scpp, char *leafp)
511 {
512     long code;
513     char tbuffer[1024];
514     char *tp, *jp;
515     cm_scache_t *substRootp = NULL;
516     char *inpathp;
517     int free_path = FALSE;
518
519     inpathp = ioctlp->inDatap;
520
521     /* If the string starts with our UTF-8 prefix (which is the
522        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
523        strings), we assume that the provided path is UTF-8.  Otherwise
524        we have to convert the string to UTF-8, since that is what we
525        want to use everywhere else.*/
526
527     if (memcmp(inpathp, utf8_prefix, utf8_prefix_size) == 0) {
528         int len, normalized_len;
529         char * normalized_path;
530
531         /* String is UTF-8 */
532         inpathp += utf8_prefix_size;
533         ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
534
535         len = strlen(inpathp) + 1;
536
537         normalized_len = cm_NormalizeUtf8String(inpathp, len, NULL, 0);
538
539         if (normalized_len > len) {
540             normalized_path = malloc(normalized_len);
541             free_path = TRUE;
542         } else {
543             normalized_path = inpathp;
544         }
545
546         cm_NormalizeUtf8String(inpathp, len, normalized_path, normalized_len);
547
548         if (normalized_path != inpathp)
549             inpathp = normalized_path;
550     } else {
551         /* Not a UTF-8 string */
552         /* TODO: If this is an OEM string, we should convert it to
553            UTF-8. */
554     }
555
556     StringCbCopyA(tbuffer, sizeof(tbuffer), inpathp);
557     tp = strrchr(tbuffer, '\\');
558     jp = strrchr(tbuffer, '/');
559     if (!tp)
560         tp = jp;
561     else if (jp && (tp - tbuffer) < (jp - tbuffer))
562         tp = jp;
563     if (!tp) {
564         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
565         if (leafp) 
566             StringCbCopyA(leafp, LEAF_SIZE, inpathp);
567     }
568     else {
569         *tp = 0;
570         if (leafp) 
571             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
572     }   
573
574     if (free_path)
575         free(inpathp);
576     inpathp = NULL;             /* We don't need this from this point on */
577
578     if (tbuffer[0] == tbuffer[1] &&
579         tbuffer[1] == '\\' && 
580         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
581     {
582         char shareName[256];
583         char *sharePath;
584         int shareFound, i;
585
586         /* We may have found a UNC path. 
587          * If the first component is the NetbiosName,
588          * then throw out the second component (the submount)
589          * since it had better expand into the value of ioctl->tidPathp
590          */
591         char * p;
592         p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
593         if ( !_strnicmp("all", p, 3) )
594             p += 4;
595
596         for (i = 0; *p && *p != '\\'; i++,p++ ) {
597             shareName[i] = *p;
598         }
599         p++;                    /* skip past trailing slash */
600         shareName[i] = 0;       /* terminate string */
601
602         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
603         if ( shareFound ) {
604             /* we found a sharename, therefore use the resulting path */
605             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
606                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
607                              userp, sharePath, reqp, &substRootp);
608             free(sharePath);
609             if (code) return code;
610
611             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
612                              userp, NULL, reqp, scpp);
613             cm_ReleaseSCache(substRootp);
614             if (code) return code;
615         } else {
616             /* otherwise, treat the name as a cellname mounted off the afs root.
617              * This requires that we reconstruct the shareName string with 
618              * leading and trailing slashes.
619              */
620             p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
621             if ( !_strnicmp("all", p, 3) )
622                 p += 4;
623
624             shareName[0] = '/';
625             for (i = 1; *p && *p != '\\'; i++,p++ ) {
626                 shareName[i] = *p;
627             }
628             p++;                    /* skip past trailing slash */
629             shareName[i++] = '/';       /* add trailing slash */
630             shareName[i] = 0;       /* terminate string */
631
632             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
633                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
634                              userp, shareName, reqp, &substRootp);
635             if (code) return code;
636
637             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
638                             userp, NULL, reqp, scpp);
639             cm_ReleaseSCache(substRootp);
640             if (code) return code;
641         }
642     } else {
643         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
644                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
645                         userp, ioctlp->tidPathp, reqp, &substRootp);
646         if (code) return code;
647
648         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
649                         userp, NULL, reqp, scpp);
650         cm_ReleaseSCache(substRootp);
651         if (code) return code;
652     }
653
654     /* # of bytes of path */
655     code = (long)strlen(ioctlp->inDatap) + 1;
656     ioctlp->inDatap += code;
657
658     /* and return success */
659     return 0;
660 }
661
662 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
663 {
664     cm_conn_t *connp;
665     cm_scache_t *scp;
666     AFSOpaque acl;
667     AFSFetchStatus fileStatus;
668     AFSVolSync volSync;
669     long code;
670     AFSFid afid;
671     int tlen;
672     cm_req_t req;
673     struct rx_connection * callp;
674     cm_ioctlQueryOptions_t *optionsp;
675     afs_uint32 flags = 0;
676
677     cm_InitReq(&req);
678
679     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
680     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
681         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
682
683     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
684         cm_fid_t fid;
685         cm_SkipIoctlPath(ioctlp);
686         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
687                   optionsp->fid.vnode, optionsp->fid.unique);
688         code = cm_GetSCache(&fid, &scp, userp, &req);
689     } else {
690         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
691     }
692     if (code) 
693         return code;
694
695     /* now make the get acl call */
696 #ifdef AFS_FREELANCE_CLIENT
697     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
698         code = 0;
699         ioctlp->outDatap[0] ='\0';
700     } else
701 #endif
702     {
703         afid.Volume = scp->fid.volume;
704         afid.Vnode = scp->fid.vnode;
705         afid.Unique = scp->fid.unique;
706         do {
707             acl.AFSOpaque_val = ioctlp->outDatap;
708             acl.AFSOpaque_len = 0;
709             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
710             if (code) continue;
711
712             callp = cm_GetRxConn(connp);
713             code = RXAFS_FetchACL(callp, &afid, &acl, &fileStatus, &volSync);
714             rx_PutConnection(callp);
715
716         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
717         code = cm_MapRPCError(code, &req);
718         cm_ReleaseSCache(scp);
719
720         if (code) return code;
721     }
722     /* skip over return data */
723     tlen = (int)strlen(ioctlp->outDatap) + 1;
724     ioctlp->outDatap += tlen;
725
726     /* and return success */
727     return 0;
728 }
729
730 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
731 {
732     long code;
733     cm_scache_t *scp;
734     cm_cell_t *cellp;
735     cm_req_t req;
736     cm_ioctlQueryOptions_t *optionsp;
737     afs_uint32 flags = 0;
738
739     cm_InitReq(&req);
740
741     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
742     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
743         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
744
745     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
746         cm_fid_t fid;
747         cm_SkipIoctlPath(ioctlp);
748         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
749                   optionsp->fid.vnode, optionsp->fid.unique);
750         code = cm_GetSCache(&fid, &scp, userp, &req);
751     } else {
752         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
753     }
754     if (code) 
755         return code;
756
757 #ifdef AFS_FREELANCE_CLIENT
758     if ( cm_freelanceEnabled && 
759          scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
760          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
761          scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
762         StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
763         ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
764         code = 0;
765     } else 
766 #endif /* AFS_FREELANCE_CLIENT */
767     {
768         cellp = cm_FindCellByID(scp->fid.cell, CM_FLAG_NOPROBE);
769         if (cellp) {
770             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
771             ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
772             code = 0;
773         }
774         else 
775             code = CM_ERROR_NOSUCHCELL;
776     }
777
778     cm_ReleaseSCache(scp);
779     return code;
780 }
781
782 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
783 {
784     cm_conn_t *connp;
785     cm_scache_t *scp;
786     AFSOpaque acl;
787     AFSFetchStatus fileStatus;
788     AFSVolSync volSync;
789     long code;
790     AFSFid fid;
791     cm_req_t req;
792     struct rx_connection * callp;
793
794     cm_InitReq(&req);
795
796     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
797     if (code) return code;
798         
799 #ifdef AFS_FREELANCE_CLIENT
800     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
801         code = CM_ERROR_NOACCESS;
802     } else
803 #endif
804     {
805         /* now make the get acl call */
806         fid.Volume = scp->fid.volume;
807         fid.Vnode = scp->fid.vnode;
808         fid.Unique = scp->fid.unique;
809         do {
810             acl.AFSOpaque_val = ioctlp->inDatap;
811             acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
812             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
813             if (code) continue;
814
815             callp = cm_GetRxConn(connp);
816             code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
817             rx_PutConnection(callp);
818
819         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
820         code = cm_MapRPCError(code, &req);
821
822         /* invalidate cache info, since we just trashed the ACL cache */
823         lock_ObtainWrite(&scp->rw);
824         cm_DiscardSCache(scp);
825         lock_ReleaseWrite(&scp->rw);
826     }
827     cm_ReleaseSCache(scp);
828
829     return code;
830 }
831
832
833
834 long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
835 {
836     long code;
837     cm_scache_t *scp;
838     int i;
839     cm_req_t req;
840
841     cm_InitReq(&req);
842
843     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
844
845     lock_ObtainWrite(&cm_scacheLock);
846     for (i=0; i<cm_data.scacheHashTableSize; i++) {
847         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
848             cm_HoldSCacheNoLock(scp);
849             lock_ReleaseWrite(&cm_scacheLock);
850
851             /* now flush the file */
852             code = cm_FlushFile(scp, userp, &req);
853             lock_ObtainWrite(&cm_scacheLock);
854             cm_ReleaseSCacheNoLock(scp);
855         }
856     }
857     lock_ReleaseWrite(&cm_scacheLock);
858
859     return code;
860 }
861
862 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
863 {
864     long code;
865     cm_scache_t *scp;
866     unsigned long volume;
867     unsigned long cell;
868     cm_req_t req;
869     cm_ioctlQueryOptions_t *optionsp;
870     afs_uint32 flags = 0;
871
872     cm_InitReq(&req);
873
874     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
875     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
876         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
877
878     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
879         cm_fid_t fid;
880         cm_SkipIoctlPath(ioctlp);
881         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
882                   optionsp->fid.vnode, optionsp->fid.unique);
883         code = cm_GetSCache(&fid, &scp, userp, &req);
884     } else {
885         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
886     }
887     if (code) 
888         return code;
889
890 #ifdef AFS_FREELANCE_CLIENT
891     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
892         code = CM_ERROR_NOACCESS;
893     } else
894 #endif
895     {
896         volume = scp->fid.volume;
897         cell = scp->fid.cell;
898         cm_ReleaseSCache(scp);
899
900         code = cm_FlushVolume(userp, &req, cell, volume);
901     }
902     return code;
903 }
904
905 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
906 {
907     long code;
908     cm_scache_t *scp;
909     cm_req_t req;
910     cm_ioctlQueryOptions_t *optionsp;
911     afs_uint32 flags = 0;
912
913     cm_InitReq(&req);
914
915     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
916     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
917         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
918
919     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
920         cm_fid_t fid;
921         cm_SkipIoctlPath(ioctlp);
922         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
923                   optionsp->fid.vnode, optionsp->fid.unique);
924         code = cm_GetSCache(&fid, &scp, userp, &req);
925     } else {
926         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
927     }
928     if (code) 
929         return code;
930
931 #ifdef AFS_FREELANCE_CLIENT
932     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
933         code = CM_ERROR_NOACCESS;
934     } else
935 #endif
936     {
937         cm_FlushFile(scp, userp, &req);
938     }
939     cm_ReleaseSCache(scp);
940
941     return 0;
942 }
943
944 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
945 {
946     cm_scache_t *scp;
947     char volName[32];
948     char offLineMsg[256];
949     char motd[256];
950     cm_conn_t *tcp;
951     long code;
952     AFSFetchVolumeStatus volStat;
953     AFSStoreVolumeStatus storeStat;
954     cm_volume_t *tvp;
955     char *cp;
956     cm_cell_t *cellp;
957     cm_req_t req;
958     struct rx_connection * callp;
959     int len;
960
961     cm_InitReq(&req);
962
963     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
964     if (code) return code;
965
966 #ifdef AFS_FREELANCE_CLIENT
967     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
968         code = CM_ERROR_NOACCESS;
969     } else
970 #endif
971     {
972         cellp = cm_FindCellByID(scp->fid.cell, 0);
973         osi_assertx(cellp, "null cm_cell_t");
974
975         if (scp->flags & CM_SCACHEFLAG_RO) {
976             cm_ReleaseSCache(scp);
977             return CM_ERROR_READONLY;
978         }
979
980         code = cm_FindVolumeByID(cellp, scp->fid.volume, userp, &req, 
981                                  CM_GETVOL_FLAG_CREATE, &tvp);
982         if (code) {
983             cm_ReleaseSCache(scp);
984             return code;
985         }
986         cm_PutVolume(tvp);
987
988         /* Copy the junk out, using cp as a roving pointer. */
989         cp = ioctlp->inDatap;
990         memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
991         cp += sizeof(AFSFetchVolumeStatus);
992
993         len = strlen(cp) + 1;
994         cm_NormalizeUtf8String(cp, len, volName, sizeof(volName));
995         cp += len;
996
997         len = strlen(cp) + 1;
998         cm_NormalizeUtf8String(cp, len, offLineMsg, sizeof(offLineMsg));
999         cp +=  len;
1000
1001         len = strlen(cp) + 1;
1002         cm_NormalizeUtf8String(cp, len, motd, sizeof(motd));
1003         storeStat.Mask = 0;
1004         if (volStat.MinQuota != -1) {
1005             storeStat.MinQuota = volStat.MinQuota;
1006             storeStat.Mask |= AFS_SETMINQUOTA;
1007         }
1008         if (volStat.MaxQuota != -1) {
1009             storeStat.MaxQuota = volStat.MaxQuota;
1010             storeStat.Mask |= AFS_SETMAXQUOTA;
1011         }
1012
1013         do {
1014             code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
1015             if (code) continue;
1016
1017             callp = cm_GetRxConn(tcp);
1018             code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
1019                                           &storeStat, volName, offLineMsg, motd);
1020             rx_PutConnection(callp);
1021
1022         } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
1023         code = cm_MapRPCError(code, &req);
1024     }
1025     
1026     /* return on failure */
1027     cm_ReleaseSCache(scp);
1028     if (code) {
1029         return code;
1030     }
1031
1032     /* we are sending parms back to make compat. with prev system.  should
1033      * change interface later to not ask for current status, just set
1034      * new status
1035      */
1036     cp = ioctlp->outDatap;
1037     memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
1038     cp += sizeof(VolumeStatus);
1039     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
1040     cp += strlen(volName)+1;
1041     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
1042     cp += strlen(offLineMsg)+1;
1043     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
1044     cp += strlen(motd)+1;
1045
1046     /* now return updated return data pointer */
1047     ioctlp->outDatap = cp;
1048
1049     return 0;
1050 }       
1051
1052 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1053 {
1054     char volName[32];
1055     cm_scache_t *scp;
1056     char offLineMsg[256];
1057     char motd[256];
1058     cm_conn_t *connp;
1059     register long code;
1060     AFSFetchVolumeStatus volStat;
1061     register char *cp;
1062     char *Name;
1063     char *OfflineMsg;
1064     char *MOTD;
1065     cm_req_t req;
1066     struct rx_connection * callp;
1067     cm_ioctlQueryOptions_t *optionsp;
1068     afs_uint32 flags = 0;
1069
1070     cm_InitReq(&req);
1071
1072     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
1073     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1074         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1075
1076     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1077         cm_fid_t fid;
1078         cm_SkipIoctlPath(ioctlp);
1079         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1080                   optionsp->fid.vnode, optionsp->fid.unique);
1081         code = cm_GetSCache(&fid, &scp, userp, &req);
1082     } else {
1083         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1084     }
1085     if (code) 
1086         return code;
1087
1088 #ifdef AFS_FREELANCE_CLIENT
1089     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
1090         code = 0;
1091         strncpy(volName, "Freelance.Local.Root", sizeof(volName));
1092         offLineMsg[0] = '\0';
1093         strncpy(motd, "Freelance mode in use.", sizeof(motd));
1094         volStat.Vid = scp->fid.volume;
1095         volStat.MaxQuota = 0;
1096         volStat.BlocksInUse = 100;
1097         volStat.PartBlocksAvail = 0;
1098         volStat.PartMaxBlocks = 100;
1099     } else
1100 #endif
1101     {
1102         Name = volName;
1103         OfflineMsg = offLineMsg;
1104         MOTD = motd;
1105         do {
1106             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
1107             if (code) continue;
1108
1109             callp = cm_GetRxConn(connp);
1110             code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
1111                                          &volStat, &Name, &OfflineMsg, &MOTD);
1112             rx_PutConnection(callp);
1113
1114         } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
1115         code = cm_MapRPCError(code, &req);
1116     }
1117
1118     cm_ReleaseSCache(scp);
1119     if (code) return code;
1120
1121     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1122     cp = ioctlp->outDatap;
1123     memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
1124     cp += sizeof(AFSFetchVolumeStatus);
1125     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
1126     cp += strlen(volName)+1;
1127     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
1128     cp += strlen(offLineMsg)+1;
1129     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
1130     cp += strlen(motd)+1;
1131
1132     /* return new size */
1133     ioctlp->outDatap = cp;
1134
1135     return 0;
1136 }
1137
1138 long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
1139 {
1140     cm_scache_t *scp;
1141     register long code;
1142     register char *cp;
1143     cm_fid_t fid;
1144     cm_req_t req;
1145     cm_ioctlQueryOptions_t * optionsp;
1146     afs_uint32 flags = 0;
1147
1148     cm_InitReq(&req);
1149
1150     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
1151     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1152         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1153
1154     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1155     if (code) return code;
1156
1157     memset(&fid, 0, sizeof(cm_fid_t));
1158     fid.cell   = scp->fid.cell;
1159     fid.volume = scp->fid.volume;
1160     fid.vnode  = scp->fid.vnode;
1161     fid.unique = scp->fid.unique;
1162
1163     cm_ReleaseSCache(scp);
1164
1165     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1166     cp = ioctlp->outDatap;
1167     memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
1168     cp += sizeof(cm_fid_t);
1169
1170     /* return new size */
1171     ioctlp->outDatap = cp;
1172
1173     return 0;
1174 }
1175
1176 long cm_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
1177 {
1178     cm_scache_t *scp;
1179     register long code;
1180     register char *cp;
1181     afs_uint32 fileType = 0;
1182     cm_req_t req;
1183     cm_ioctlQueryOptions_t * optionsp;
1184     afs_uint32 flags = 0;
1185
1186     cm_InitReq(&req);
1187
1188     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
1189     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1190         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1191
1192     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1193         cm_fid_t fid;
1194         cm_SkipIoctlPath(ioctlp);
1195         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1196                   optionsp->fid.vnode, optionsp->fid.unique);
1197         code = cm_GetSCache(&fid, &scp, userp, &req);
1198     } else {
1199         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1200     }
1201     if (code) 
1202         return code;
1203
1204     fileType = scp->fileType;
1205     cm_ReleaseSCache(scp);
1206
1207     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1208     cp = ioctlp->outDatap;
1209     memcpy(cp, (char *)&fileType, sizeof(fileType));
1210     cp += sizeof(fileType);
1211
1212     /* return new size */
1213     ioctlp->outDatap = cp;
1214
1215     return 0;
1216 }
1217
1218 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
1219 {
1220     cm_scache_t *scp;
1221     register long code;
1222     register char *cp;
1223     cm_req_t req;
1224     cm_ioctlQueryOptions_t *optionsp;
1225     afs_uint32 flags = 0;
1226
1227     cm_InitReq(&req);
1228
1229     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
1230     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1231         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1232
1233     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1234         cm_fid_t fid;
1235         cm_SkipIoctlPath(ioctlp);
1236         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1237                   optionsp->fid.vnode, optionsp->fid.unique);
1238         code = cm_GetSCache(&fid, &scp, userp, &req);
1239     } else {
1240         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1241     }
1242     if (code) 
1243         return code;
1244
1245     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1246     cp = ioctlp->outDatap;
1247     memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
1248     cp += sizeof(afs_uint32);
1249     memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
1250     cp += sizeof(afs_uint32);
1251
1252     /* return new size */
1253     ioctlp->outDatap = cp;
1254
1255     cm_ReleaseSCache(scp);
1256
1257     return 0;
1258 }
1259
1260 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1261 {
1262     long code;
1263     cm_scache_t *scp;
1264     cm_cell_t *cellp;
1265     cm_volume_t *tvp;
1266     cm_serverRef_t **tsrpp, *current;
1267     cm_server_t *tsp;
1268     unsigned long volume;
1269     char *cp;
1270     cm_req_t req;
1271     cm_ioctlQueryOptions_t *optionsp;
1272     afs_uint32 flags = 0;
1273
1274     cm_InitReq(&req);
1275
1276     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
1277     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1278         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1279
1280     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1281         cm_fid_t fid;
1282         cm_SkipIoctlPath(ioctlp);
1283         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1284                   optionsp->fid.vnode, optionsp->fid.unique);
1285         code = cm_GetSCache(&fid, &scp, userp, &req);
1286     } else {
1287         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1288     }
1289     if (code) 
1290         return code;
1291
1292     volume = scp->fid.volume;
1293
1294     cellp = cm_FindCellByID(scp->fid.cell, 0);
1295
1296     cm_ReleaseSCache(scp);
1297
1298     if (!cellp)
1299         return CM_ERROR_NOSUCHCELL;
1300
1301 #ifdef AFS_FREELANCE_CLIENT
1302     if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID) {
1303         struct in_addr addr;
1304
1305         addr.s_net = 127;
1306         addr.s_host = 0;
1307         addr.s_lh = 0;
1308         addr.s_impno = 1;
1309
1310         cp = ioctlp->outDatap;
1311         
1312         memcpy(cp, (char *)&addr, sizeof(addr));
1313         cp += sizeof(addr);
1314
1315         /* still room for terminating NULL, add it on */
1316         addr.s_addr = 0;
1317         memcpy(cp, (char *)&addr, sizeof(addr));
1318         cp += sizeof(addr);
1319
1320         ioctlp->outDatap = cp;
1321     } else 
1322 #endif
1323     {
1324         code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
1325         if (code) 
1326             return code;
1327         
1328         cp = ioctlp->outDatap;
1329         
1330         tsrpp = cm_GetVolServers(tvp, volume);
1331         lock_ObtainRead(&cm_serverLock);
1332         for (current = *tsrpp; current; current = current->next) {
1333             tsp = current->server;
1334             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1335             cp += sizeof(long);
1336         }
1337         lock_ReleaseRead(&cm_serverLock);
1338         cm_FreeServerList(tsrpp, 0);
1339
1340         /* still room for terminating NULL, add it on */
1341         volume = 0;     /* reuse vbl */
1342         memcpy(cp, (char *)&volume, sizeof(long));
1343         cp += sizeof(long);
1344
1345         ioctlp->outDatap = cp;
1346         cm_PutVolume(tvp);
1347     }
1348     return 0;
1349 }       
1350
1351 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1352 {
1353     long code;
1354     cm_scache_t *dscp;
1355     cm_scache_t *scp;
1356     char *cp;
1357     cm_req_t req;
1358
1359     cm_InitReq(&req);
1360
1361     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1362     if (code) return code;
1363
1364     cp = ioctlp->inDatap;
1365
1366     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1367     cm_ReleaseSCache(dscp);
1368     if (code) return code;
1369         
1370     lock_ObtainWrite(&scp->rw);
1371
1372     /* now check that this is a real mount point */
1373     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1374         lock_ReleaseWrite(&scp->rw);
1375         cm_ReleaseSCache(scp);
1376         return CM_ERROR_INVAL;
1377     }
1378
1379     code = cm_ReadMountPoint(scp, userp, &req);
1380     if (code == 0) {
1381         cp = ioctlp->outDatap;
1382         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1383         cp += strlen(cp) + 1;
1384         ioctlp->outDatap = cp;
1385     }
1386     lock_ReleaseWrite(&scp->rw);
1387     cm_ReleaseSCache(scp);
1388
1389     return code;
1390 }       
1391
1392 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1393 {
1394     long code;
1395     cm_scache_t *dscp;
1396     cm_scache_t *scp;
1397     char *cp;
1398     cm_req_t req;
1399
1400     cm_InitReq(&req);
1401
1402     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1403     if (code) return code;
1404
1405     cp = ioctlp->inDatap;
1406
1407     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1408         
1409     /* if something went wrong, bail out now */
1410     if (code)
1411         goto done3;
1412         
1413     lock_ObtainWrite(&scp->rw);
1414     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1415                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1416     if (code)  
1417         goto done2;
1418
1419     /* now check that this is a real mount point */
1420     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1421         code = CM_ERROR_INVAL;
1422         goto done1;
1423     }
1424
1425     /* time to make the RPC, so drop the lock */
1426     lock_ReleaseWrite(&scp->rw);
1427
1428 #ifdef AFS_FREELANCE_CLIENT
1429     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1430         /* we are adding the mount point to the root dir., so call
1431          * the freelance code to do the add. */
1432         osi_Log0(afsd_logp,"IoctlDeleteMountPoint from Freelance root dir");
1433         code = cm_FreelanceRemoveMount(cp);
1434     } else 
1435 #endif
1436     {
1437         /* easier to do it this way */
1438         code = cm_Unlink(dscp, cp, userp, &req);
1439     }
1440     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1441         smb_NotifyChange(FILE_ACTION_REMOVED,
1442                           FILE_NOTIFY_CHANGE_DIR_NAME,
1443                           dscp, cp, NULL, TRUE);
1444
1445     lock_ObtainWrite(&scp->rw);
1446   done1:
1447     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1448
1449   done2:
1450     cm_DiscardSCache(scp);
1451     lock_ReleaseWrite(&scp->rw);
1452     cm_ReleaseSCache(scp);
1453
1454   done3:
1455     cm_ReleaseSCache(dscp);
1456     return code;
1457 }
1458
1459 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1460 {
1461     cm_cell_t *cellp;
1462     chservinfo_t csi;
1463     char *tp;
1464     char *cp;
1465     long temp;
1466     cm_server_t *tsp;
1467     int haveCell;
1468         
1469     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
1470     tp = ioctlp->inDatap;
1471     haveCell = 0;
1472
1473     memcpy(&temp, tp, sizeof(temp));
1474     if (temp == 0x12345678) {   /* For afs3.3 version */
1475         memcpy(&csi, tp, sizeof(csi));
1476         if (csi.tinterval >= 0) {
1477             cp = ioctlp->outDatap;
1478             memcpy(cp, (char *)&cm_daemonCheckDownInterval, sizeof(long));
1479             ioctlp->outDatap += sizeof(long);
1480             if (csi.tinterval > 0) {
1481                 if (!smb_SUser(userp))
1482                     return CM_ERROR_NOACCESS;
1483                 cm_daemonCheckDownInterval = csi.tinterval;
1484             }
1485             return 0;
1486         }
1487         if (csi.tsize)
1488             haveCell = 1;
1489         temp = csi.tflags;
1490         cp = csi.tbuffer;
1491     } else {    /* For pre afs3.3 versions */
1492         memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1493         ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
1494         if (cp - ioctlp->inAllocp < ioctlp->inCopied)   /* still more data available */
1495             haveCell = 1;
1496     }       
1497
1498     /* 
1499      * 1: fast check, don't contact servers.
1500      * 2: local cell only.
1501      */
1502     if (haveCell) {
1503         /* have cell name, too */
1504         cellp = cm_GetCell(cp, (temp & 1) ? CM_FLAG_NOPROBE : 0);
1505         if (!cellp) 
1506             return CM_ERROR_NOSUCHCELL;
1507     }
1508     else cellp = (cm_cell_t *) 0;
1509     if (!cellp && (temp & 2)) {
1510         /* use local cell */
1511         cellp = cm_FindCellByID(1, 0);
1512     }
1513     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1514         /* check down servers */
1515         cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
1516                          cellp);
1517     }       
1518
1519     /* now return the current down server list */
1520     cp = ioctlp->outDatap;
1521     lock_ObtainRead(&cm_serverLock);
1522     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
1523         if (cellp && tsp->cellp != cellp) continue;     /* cell spec'd and wrong */
1524         if ((tsp->flags & CM_SERVERFLAG_DOWN)
1525              && tsp->type == CM_SERVER_FILE) {
1526             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1527             cp += sizeof(long);
1528         }
1529     }
1530     lock_ReleaseRead(&cm_serverLock);
1531
1532     ioctlp->outDatap = cp;
1533     return 0;
1534 }
1535
1536 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1537 {
1538     /* we don't print anything superfluous, so we don't support the gag call */
1539     return CM_ERROR_INVAL;
1540 }
1541
1542 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1543 {
1544     cm_RefreshVolumes();
1545     return 0;
1546 }       
1547
1548 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1549 {
1550     afs_uint64 temp;
1551     long code;
1552
1553     cm_SkipIoctlPath(ioctlp);
1554
1555     memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1556     if (temp == 0) 
1557         temp = cm_data.buf_nOrigBuffers;
1558     else {
1559         /* temp is in 1K units, convert to # of buffers */
1560         temp = temp / (cm_data.buf_blockSize / 1024);
1561     }       
1562
1563     /* now adjust the cache size */
1564     code = buf_SetNBuffers(temp);
1565
1566     return code;
1567 }
1568
1569 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1570 {
1571     long inValue;
1572         
1573     cm_SkipIoctlPath(ioctlp);
1574         
1575     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1576
1577     /* print trace */
1578     if (inValue & 8) {
1579         afsd_ForceTrace(FALSE);
1580         buf_ForceTrace(FALSE);
1581     }
1582         
1583     if (inValue & 2) {
1584         /* set tracing value to low order bit */
1585         if ((inValue & 1) == 0) {
1586             /* disable tracing */
1587             osi_LogDisable(afsd_logp);
1588             rx_DebugOnOff(FALSE);
1589         }
1590         else {
1591             /* enable tracing */
1592             osi_LogEnable(afsd_logp);
1593             rx_DebugOnOff(TRUE);
1594         }
1595     }
1596
1597     /* see if we're supposed to do a reset, too */
1598     if (inValue & 4) {
1599         osi_LogReset(afsd_logp);
1600     }
1601
1602     /* and copy out tracing flag */
1603     inValue = afsd_logp->enabled;       /* use as a temp vbl */
1604     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1605     ioctlp->outDatap += sizeof(long);
1606     return 0;
1607 }       
1608
1609 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1610 {
1611     cm_cacheParms_t parms;
1612
1613     memset(&parms, 0, sizeof(parms));
1614
1615     /* first we get, in 1K units, the cache size */
1616     parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1617
1618     /* and then the actual # of buffers in use (not in the free list, I guess,
1619      * will be what we do).
1620      */
1621     parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1622
1623     memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1624     ioctlp->outDatap += sizeof(parms);
1625
1626     return 0;
1627 }
1628
1629 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1630 {
1631     long whichCell;
1632     long magic = 0;
1633     cm_cell_t *tcellp;
1634     cm_serverRef_t *serverRefp;
1635     cm_server_t *serverp;
1636     long i;
1637     char *cp;
1638     char *tp;
1639     char *basep;
1640
1641     cm_SkipIoctlPath(ioctlp);
1642
1643     tp = ioctlp->inDatap;
1644
1645     memcpy((char *)&whichCell, tp, sizeof(long));
1646     tp += sizeof(long);
1647
1648     /* see if more than one long passed in, ignoring the null pathname (the -1) */
1649     if (ioctlp->inCopied-1 > sizeof(long)) {
1650         memcpy((char *)&magic, tp, sizeof(long));
1651     }
1652
1653     lock_ObtainRead(&cm_cellLock);
1654     for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
1655         if (whichCell == 0) break;
1656         whichCell--;
1657     }
1658     lock_ReleaseRead(&cm_cellLock);
1659     if (tcellp) {
1660         int max = 8;
1661
1662         cp = ioctlp->outDatap;
1663
1664         if (magic == 0x12345678) {
1665             memcpy(cp, (char *)&magic, sizeof(long));
1666             max = 13;
1667         }
1668         memset(cp, 0, max * sizeof(long));
1669         basep = cp;
1670         lock_ObtainRead(&cm_serverLock);        /* for going down server list */
1671         /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1672         serverRefp = tcellp->vlServersp;
1673         for (i=0; i<max; i++) {
1674             if (!serverRefp) break;
1675             serverp = serverRefp->server;
1676             memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1677             cp += sizeof(long);
1678             serverRefp = serverRefp->next;
1679         }
1680         lock_ReleaseRead(&cm_serverLock);
1681         cp = basep + max * sizeof(afs_int32);
1682         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
1683         cp += strlen(tcellp->name)+1;
1684         ioctlp->outDatap = cp;
1685     }
1686
1687     if (tcellp) 
1688         return 0;
1689     else 
1690         return CM_ERROR_NOMORETOKENS;   /* mapped to EDOM */
1691 }
1692
1693 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1694 {
1695     /* NT cache manager will read cell information from CellServDB each time
1696      * cell is accessed. So, this call is necessary only if list of server for a cell 
1697      * changes (or IP addresses of cell servers changes).
1698      * All that needs to be done is to refresh server information for all cells that 
1699      * are already loaded.
1700   
1701      * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1702      */  
1703   
1704     cm_cell_t *cp;
1705     cm_cell_rock_t rock;
1706
1707   
1708     cm_SkipIoctlPath(ioctlp);
1709     lock_ObtainWrite(&cm_cellLock);
1710   
1711     for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
1712     {
1713         long code;
1714         lock_ObtainMutex(&cp->mx);
1715         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1716         cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
1717         cp->vlServersp = NULL;
1718         rock.cellp = cp;
1719         rock.flags = 0;
1720         code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, &rock);
1721 #ifdef AFS_AFSDB_ENV
1722         if (code) {
1723             if (cm_dnsEnabled) {
1724                 int ttl;
1725                 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, &rock);
1726                 if ( code == 0 ) { /* got cell from DNS */
1727                     cp->flags |= CM_CELLFLAG_DNS;
1728                     cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1729                     cp->timeout = time(0) + ttl;
1730                 }
1731             }
1732         } 
1733         else {
1734             cp->flags &= ~CM_CELLFLAG_DNS;
1735         }
1736 #endif /* AFS_AFSDB_ENV */
1737         if (code) {
1738             cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1739         }
1740         else {
1741             cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1742             cm_RandomizeServer(&cp->vlServersp);
1743         }
1744         lock_ReleaseMutex(&cp->mx);
1745     }
1746     
1747     lock_ReleaseWrite(&cm_cellLock);
1748     return 0;       
1749 }
1750
1751 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1752 {
1753         long code = 0;
1754
1755         if (cm_freelanceEnabled) {
1756             if (cm_GetRootCellName(ioctlp->outDatap))
1757                 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
1758             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1759         } else if (cm_data.rootCellp) {
1760             /* return the default cellname to the caller */
1761             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
1762             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1763         } else {
1764             /* if we don't know our default cell, return failure */
1765             code = CM_ERROR_NOSUCHCELL;
1766     }
1767
1768     return code;
1769 }
1770
1771 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1772 {
1773     long setSysName, foundname = 0;
1774     char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1775     int t, count, num = 0;
1776     char **sysnamelist[MAXSYSNAME];
1777         
1778     cm_SkipIoctlPath(ioctlp);
1779
1780     memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1781     ioctlp->inDatap += sizeof(long);
1782         
1783     if (setSysName) {
1784         /* check my args */
1785         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1786             return EINVAL;
1787         cp2 = ioctlp->inDatap;
1788         for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1789             /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1790             t = (int)strlen(cp);
1791             if (t >= MAXSYSNAME || t <= 0)
1792                 return EINVAL;
1793             /* check for names that can shoot us in the foot */
1794             if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1795                 return EINVAL;
1796             cp += t + 1;
1797         }
1798         /* args ok */
1799
1800         /* inname gets first entry in case we're being a translator */
1801         /* (we are never a translator) */
1802         t = (int)strlen(ioctlp->inDatap);
1803         memcpy(inname, ioctlp->inDatap, t + 1);
1804         ioctlp->inDatap += t + 1;
1805         num = count;
1806     }
1807
1808     /* Not xlating, so local case */
1809     if (!cm_sysName)
1810         osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1811
1812     if (!setSysName) {      /* user just wants the info */
1813         StringCbCopyA(outname, sizeof(outname), cm_sysName);
1814         foundname = cm_sysNameCount;
1815         *sysnamelist = cm_sysNameList;
1816     } else {        
1817         /* Local guy; only root can change sysname */
1818         /* clear @sys entries from the dnlc, once afs_lookup can
1819          * do lookups of @sys entries and thinks it can trust them */
1820         /* privs ok, store the entry, ... */
1821         StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1822         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1823         if (setSysName > 1) {       /* ... or list */
1824             cp = ioctlp->inDatap;
1825             for (count = 1; count < setSysName; ++count) {
1826                 if (!cm_sysNameList[count])
1827                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1828                                __FILE__, __LINE__);
1829                 t = (int)strlen(cp);
1830                 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1831                 cp += t + 1;
1832             }
1833         }
1834         cm_sysNameCount = setSysName;
1835     }
1836
1837     if (!setSysName) {
1838         /* return the sysname to the caller */
1839         cp = ioctlp->outDatap;
1840         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1841         cp += sizeof(afs_int32);        /* skip found flag */
1842         if (foundname) {
1843             StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
1844             cp += strlen(outname) + 1;  /* skip name and terminating null char */
1845             for ( count=1; count < foundname ; ++count) {   /* ... or list */
1846                 if ( !(*sysnamelist)[count] )
1847                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
1848                                __FILE__, __LINE__);
1849                 t = (int)strlen((*sysnamelist)[count]);
1850                 if (t >= MAXSYSNAME)
1851                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
1852                                __FILE__, __LINE__);
1853                 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
1854                 cp += t + 1;
1855             }
1856         }
1857         ioctlp->outDatap = cp;
1858     }
1859         
1860     /* done: success */
1861     return 0;
1862 }
1863
1864 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1865 {
1866     long temp;
1867     cm_cell_t *cellp;
1868
1869     cm_SkipIoctlPath(ioctlp);
1870
1871     cellp = cm_GetCell(ioctlp->inDatap, 0);
1872     if (!cellp) 
1873         return CM_ERROR_NOSUCHCELL;
1874
1875     temp = 0;
1876     lock_ObtainMutex(&cellp->mx);
1877     if (cellp->flags & CM_CELLFLAG_SUID)
1878         temp |= CM_SETCELLFLAG_SUID;
1879     lock_ReleaseMutex(&cellp->mx);
1880         
1881     /* now copy out parm */
1882     memcpy(ioctlp->outDatap, &temp, sizeof(long));
1883     ioctlp->outDatap += sizeof(long);
1884
1885     return 0;
1886 }
1887
1888 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1889 {
1890     long temp;
1891     cm_cell_t *cellp;
1892
1893     cm_SkipIoctlPath(ioctlp);
1894
1895     cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1896     if (!cellp) 
1897         return CM_ERROR_NOSUCHCELL;
1898
1899     memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1900
1901     lock_ObtainMutex(&cellp->mx);
1902     if (temp & CM_SETCELLFLAG_SUID)
1903         cellp->flags |= CM_CELLFLAG_SUID;
1904     else
1905         cellp->flags &= ~CM_CELLFLAG_SUID;
1906     lock_ReleaseMutex(&cellp->mx);
1907
1908     return 0;
1909 }
1910
1911 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1912 {
1913     cm_SSetPref_t         *spin; /* input */
1914     cm_SPref_t        *srvin;   /* one input component */
1915     cm_server_t       *tsp;
1916     int                   i, vlonly, noServers, type;
1917     struct sockaddr_in  tmp;
1918     unsigned short        rank;
1919
1920     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1921
1922     spin           = (cm_SSetPref_t *)ioctlp->inDatap;
1923     noServers  = spin->num_servers;
1924     vlonly     = spin->flags;
1925     if ( vlonly )
1926         type = CM_SERVER_VLDB;
1927     else    
1928         type = CM_SERVER_FILE;
1929
1930     for ( i=0; i < noServers; i++) 
1931     {
1932         srvin          = &(spin->servers[i]);
1933         rank           = srvin->rank + (rand() & 0x000f);
1934         tmp.sin_addr   = srvin->host;
1935         tmp.sin_family = AF_INET;
1936
1937         tsp = cm_FindServer(&tmp, type);
1938         if ( tsp )              /* an existing server - ref count increased */
1939         {
1940             tsp->ipRank = rank; /* no need to protect by mutex*/
1941
1942             if (type == CM_SERVER_FILE)
1943             {   /* fileserver */
1944                 /* find volumes which might have RO copy 
1945                 /* on server and change the ordering of 
1946                  * their RO list 
1947                  */
1948                 cm_ChangeRankVolume(tsp);
1949             }
1950             else        
1951             {
1952                 /* set preferences for an existing vlserver */
1953                 cm_ChangeRankCellVLServer(tsp);
1954             }
1955         }
1956         else    /* add a new server without a cell */
1957         {
1958             tsp = cm_NewServer(&tmp, type, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
1959             tsp->ipRank = rank;
1960         }
1961         lock_ObtainMutex(&tsp->mx);
1962         tsp->flags |= CM_SERVERFLAG_PREF_SET;
1963         lock_ReleaseMutex(&tsp->mx);
1964         cm_PutServer(tsp);  /* decrease refcount */
1965     }
1966     return 0;
1967 }
1968
1969 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1970 {
1971     cm_SPrefRequest_t *spin; /* input */
1972     cm_SPrefInfo_t    *spout;   /* output */
1973     cm_SPref_t        *srvout;   /* one output component */
1974     cm_server_t       *tsp;
1975     int                   i, vlonly, noServers;
1976
1977     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1978
1979     spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
1980     spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
1981     srvout    = spout->servers;
1982     noServers = spin->num_servers; 
1983     vlonly    = spin->flags & CM_SPREF_VLONLY;
1984     spout->num_servers = 0;
1985
1986     lock_ObtainRead(&cm_serverLock); /* get server lock */
1987
1988     for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1989         if (spin->offset > i) {
1990             continue;    /* catch up to where we left off */
1991         }
1992
1993         if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1994             continue;   /* ignore fileserver for -vlserver option*/
1995         if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1996             continue;   /* ignore vlservers */
1997
1998         srvout->host = tsp->addr.sin_addr;
1999         srvout->rank = tsp->ipRank;
2000         srvout++;       
2001         spout->num_servers++;
2002         noServers--;
2003     }
2004     lock_ReleaseRead(&cm_serverLock); /* release server lock */
2005
2006     if ( tsp )  /* we ran out of space in the output buffer */
2007         spout->next_offset = i;
2008     else    
2009         spout->next_offset = 0; 
2010     ioctlp->outDatap += sizeof(cm_SPrefInfo_t) + 
2011         (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
2012     return 0;
2013 }
2014
2015 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
2016 {
2017     /* we ignore default asynchrony since we only have one way
2018      * of doing this today.
2019      */
2020     return 0;
2021 }       
2022
2023 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
2024 {
2025     char leaf[LEAF_SIZE];
2026     long code;
2027     cm_scache_t *dscp;
2028     cm_attr_t tattr;
2029     char *cp;
2030     cm_req_t req;
2031     char mpInfo[256];
2032     char fullCell[256];
2033     char volume[256];
2034     char cell[256];
2035     int ttl;
2036
2037     cm_InitReq(&req);
2038         
2039     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
2040     if (code) 
2041         return code;
2042
2043     /* Translate chars for the mount point name */
2044     if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
2045     TranslateExtendedChars(leaf);
2046     }
2047
2048     /* 
2049      * The fs command allows the user to specify partial cell names on NT.  These must
2050      * be expanded to the full cell name for mount points so that the mount points will
2051      * work on UNIX clients.
2052      */
2053
2054     /* Extract the possibly partial cell name */
2055     StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
2056         
2057     if (cp = strchr(cell, ':')) {
2058         /* Extract the volume name */
2059         *cp = 0;
2060         StringCbCopyA(volume,  sizeof(volume), cp + 1);
2061         
2062         /* Get the full name for this cell */
2063         code = cm_SearchCellFile(cell, fullCell, 0, 0);
2064 #ifdef AFS_AFSDB_ENV
2065         if (code && cm_dnsEnabled)
2066             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
2067 #endif
2068         if (code) {
2069             cm_ReleaseSCache(dscp);
2070             return CM_ERROR_NOSUCHCELL;
2071         }
2072         
2073         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
2074     } else {
2075         /* No cell name specified */
2076         StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
2077     }
2078
2079 #ifdef AFS_FREELANCE_CLIENT
2080     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
2081         /* we are adding the mount point to the root dir., so call
2082          * the freelance code to do the add. */
2083         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
2084         code = cm_FreelanceAddMount(leaf, fullCell, volume, 
2085                                     *ioctlp->inDatap == '%', NULL);
2086     } else 
2087 #endif
2088     {
2089         /* create the symlink with mode 644.  The lack of X bits tells
2090          * us that it is a mount point.
2091          */
2092         tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
2093         tattr.unixModeBits = 0644;
2094         tattr.clientModTime = time(NULL);
2095
2096         code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
2097     }
2098     
2099     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2100         smb_NotifyChange(FILE_ACTION_ADDED,
2101                          FILE_NOTIFY_CHANGE_DIR_NAME,
2102                          dscp, leaf, NULL, TRUE);
2103
2104     cm_ReleaseSCache(dscp);
2105     return code;
2106 }
2107
2108 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
2109 {
2110     char leaf[LEAF_SIZE];
2111     long code;
2112     cm_scache_t *dscp;
2113     cm_attr_t tattr;
2114     char *cp;
2115     cm_req_t req;
2116     char *symlp;
2117     int free_syml = FALSE;
2118
2119     cm_InitReq(&req);
2120
2121     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
2122     if (code) return code;
2123
2124     if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
2125     /* Translate chars for the link name */
2126     TranslateExtendedChars(leaf);
2127
2128     /* Translate chars for the linked to name */
2129     TranslateExtendedChars(ioctlp->inDatap);
2130     }
2131
2132     symlp = ioctlp->inDatap;            /* contents of link */
2133
2134     {
2135         char * normalized;
2136         int normalized_len;
2137
2138         int len = strlen(symlp) + 1;
2139
2140         normalized_len = cm_NormalizeUtf8String(symlp, len, NULL, 0);
2141         if (normalized_len > len) {
2142             normalized = malloc(normalized_len);
2143             free_syml = TRUE;
2144         } else {
2145             normalized = symlp;
2146         }
2147
2148         cm_NormalizeUtf8String(symlp, len, normalized, normalized_len);
2149
2150         if (symlp != normalized)
2151             symlp = normalized;
2152     }
2153
2154     cp = symlp;
2155
2156 #ifdef AFS_FREELANCE_CLIENT
2157     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
2158         /* we are adding the symlink to the root dir., so call
2159          * the freelance code to do the add. */
2160         if (cp[0] == cp[1] && cp[1] == '\\' && 
2161             !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
2162         {
2163             /* skip \\AFS\ or \\AFS\all\ */
2164             char * p;
2165             p = cp + 2 + strlen(cm_NetbiosName) + 1;
2166             if ( !_strnicmp("all", p, 3) )
2167                 p += 4;
2168             cp = p;
2169         }
2170         osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
2171         code = cm_FreelanceAddSymlink(leaf, cp, NULL);
2172     } else
2173 #endif
2174     {
2175         /* Create symlink with mode 0755. */
2176         tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
2177         tattr.unixModeBits = 0755;
2178
2179         code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
2180     }
2181
2182     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2183         smb_NotifyChange(FILE_ACTION_ADDED,
2184                           FILE_NOTIFY_CHANGE_FILE_NAME
2185                           | FILE_NOTIFY_CHANGE_DIR_NAME,
2186                           dscp, leaf, NULL, TRUE);
2187
2188     cm_ReleaseSCache(dscp);
2189
2190     if (free_syml)
2191         free(symlp);
2192
2193     return code;
2194 }
2195
2196
2197 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
2198 {
2199     long code;
2200     cm_scache_t *dscp;
2201     cm_scache_t *scp;
2202     char *cp;
2203     cm_space_t *spacep;
2204     cm_scache_t *newRootScp;
2205     cm_req_t req;
2206
2207     cm_InitReq(&req);
2208
2209     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
2210     if (code) return code;
2211
2212     cp = ioctlp->inDatap;
2213
2214     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
2215     cm_ReleaseSCache(dscp);
2216     if (code) return code;
2217
2218     /* Check that it's a real symlink */
2219     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
2220         scp->fileType != CM_SCACHETYPE_DFSLINK &&
2221         scp->fileType != CM_SCACHETYPE_INVALID) {
2222         cm_ReleaseSCache(scp);
2223         return CM_ERROR_INVAL;
2224     }
2225
2226     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
2227     cm_ReleaseSCache(scp);
2228     if (code == 0) {
2229         cp = ioctlp->outDatap;
2230         if (newRootScp != NULL) {
2231             StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
2232             StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
2233             cp += strlen(cp);
2234         }
2235         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
2236         cp += strlen(cp) + 1;
2237         ioctlp->outDatap = cp;
2238         cm_FreeSpace(spacep);
2239         if (newRootScp != NULL)
2240             cm_ReleaseSCache(newRootScp);
2241         code = 0;
2242     } else if (code == CM_ERROR_PATH_NOT_COVERED && 
2243                 scp->fileType == CM_SCACHETYPE_DFSLINK ||
2244                code == CM_ERROR_NOSUCHPATH &&
2245                 scp->fileType == CM_SCACHETYPE_INVALID) {
2246
2247         cp = ioctlp->outDatap;
2248         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
2249         cp += strlen(cp) + 1;
2250         ioctlp->outDatap = cp;
2251         code = 0;
2252     }
2253
2254     return code;
2255 }
2256
2257 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
2258 {/*CHECK FOR VALID SYMLINK*/
2259     long code;
2260     cm_scache_t *dscp;
2261     cm_scache_t *scp;
2262     char *cp;
2263     cm_req_t req;
2264
2265     cm_InitReq(&req);
2266
2267     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
2268     if (code) return code;
2269
2270     cp = ioctlp->inDatap;
2271     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
2272
2273     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
2274     cm_ReleaseSCache(dscp);
2275     if (code) return code;
2276
2277     /* Check that it's a real symlink */
2278     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
2279         scp->fileType != CM_SCACHETYPE_DFSLINK &&
2280         scp->fileType != CM_SCACHETYPE_INVALID)
2281         code = CM_ERROR_INVAL;
2282     cm_ReleaseSCache(scp);
2283     return code;
2284 }
2285
2286 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
2287 {
2288     long code;
2289     cm_scache_t *dscp;
2290     cm_scache_t *scp;
2291     char *cp;
2292     cm_req_t req;
2293
2294     cm_InitReq(&req);
2295
2296     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
2297     if (code) return code;
2298
2299     cp = ioctlp->inDatap;
2300
2301     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
2302         
2303     /* if something went wrong, bail out now */
2304     if (code)
2305         goto done3;
2306         
2307     lock_ObtainWrite(&scp->rw);
2308     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2309                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2310     if (code)
2311         goto done2;
2312         
2313     /* now check that this is a real symlink */
2314     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
2315         scp->fileType != CM_SCACHETYPE_DFSLINK &&
2316         scp->fileType != CM_SCACHETYPE_INVALID) {
2317         code = CM_ERROR_INVAL;
2318         goto done1;
2319     }
2320         
2321     /* time to make the RPC, so drop the lock */
2322     lock_ReleaseWrite(&scp->rw);
2323         
2324 #ifdef AFS_FREELANCE_CLIENT
2325     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
2326         /* we are adding the mount point to the root dir., so call
2327          * the freelance code to do the add. */
2328         osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
2329         code = cm_FreelanceRemoveSymlink(cp);
2330     } else 
2331 #endif
2332     {
2333         /* easier to do it this way */
2334         code = cm_Unlink(dscp, cp, userp, &req);
2335     }
2336     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2337         smb_NotifyChange(FILE_ACTION_REMOVED,
2338                           FILE_NOTIFY_CHANGE_FILE_NAME
2339                           | FILE_NOTIFY_CHANGE_DIR_NAME,
2340                           dscp, cp, NULL, TRUE);
2341
2342     lock_ObtainWrite(&scp->rw);
2343   done1:
2344     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2345
2346   done2:
2347     cm_DiscardSCache(scp);
2348     lock_ReleaseWrite(&scp->rw);
2349     cm_ReleaseSCache(scp);
2350
2351   done3:
2352     cm_ReleaseSCache(dscp);
2353     return code;
2354 }
2355
2356 #ifdef QUERY_AFSID
2357 long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
2358 {
2359     afs_int32 code;
2360     namelist lnames;
2361     idlist lids;
2362     static struct afsconf_cell info;
2363     struct rx_connection *serverconns[MAXSERVERS];
2364     struct rx_securityClass *sc[3];
2365     afs_int32 scIndex = 2;      /* authenticated - we have a token */
2366     struct ubik_client *pruclient = NULL;
2367     struct afsconf_dir *tdir;
2368     int i;
2369     char * p, * r;
2370
2371     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
2372     code = afsconf_GetCellInfo(tdir, ucellp->cellp->name, "afsprot", &info);
2373     afsconf_Close(tdir);
2374
2375     sc[0] = 0;
2376     sc[1] = 0;
2377     sc[2] = 0;
2378
2379     /* we have the token that was given to us in the settoken 
2380      * call.   we just have to use it. 
2381      */
2382     scIndex = 2;        /* kerberos ticket */
2383     sc[2] = rxkad_NewClientSecurityObject(rxkad_clear, &ucellp->sessionKey,
2384                                           ucellp->kvno, ucellp->ticketLen,
2385                                           ucellp->ticketp);
2386
2387     memset(serverconns, 0, sizeof(serverconns));        /* terminate list!!! */
2388     for (i = 0; i < info.numServers; i++)
2389         serverconns[i] =
2390             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
2391                              info.hostAddr[i].sin_port, PRSRV, sc[scIndex],
2392                              scIndex);
2393
2394     code = ubik_ClientInit(serverconns, &pruclient);
2395     if (code) {
2396         return code;
2397     }
2398
2399     code = rxs_Release(sc[scIndex]);
2400
2401     lids.idlist_len = 0;
2402     lids.idlist_val = 0;
2403     lnames.namelist_len = 1;
2404     lnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
2405     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
2406     lnames.namelist_val[0][PR_MAXNAMELEN-1] = '\0';
2407     for ( p=lnames.namelist_val[0], r=NULL; *p; p++ ) {
2408         if (isupper(*p))
2409             *p = tolower(*p);
2410         if (*p == '@')
2411             r = p;
2412     }
2413     if (r && !stricmp(r+1,ucellp->cellp->name))
2414         *r = '\0';
2415
2416     code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
2417     if (lids.idlist_val) {
2418         *uid = *lids.idlist_val;
2419         free(lids.idlist_val);
2420     }
2421     if (lnames.namelist_val)
2422         free(lnames.namelist_val);
2423
2424     if ( pruclient ) {
2425         ubik_ClientDestroy(pruclient);
2426         pruclient = NULL;
2427     }
2428
2429     return 0;
2430 }
2431 #endif /* QUERY_AFSID */
2432
2433 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2434 {
2435     char *saveDataPtr;
2436     char *tp;
2437     int ticketLen;
2438     char *ticket;
2439     int ctSize;
2440     struct ClearToken ct;
2441     cm_cell_t *cellp;
2442     cm_ucell_t *ucellp;
2443     char *uname = NULL;
2444     afs_uuid_t uuid;
2445     int flags;
2446     char sessionKey[8];
2447     char *smbname;
2448     int release_userp = 0;
2449     char * wdir = NULL;
2450
2451     saveDataPtr = ioctlp->inDatap;
2452
2453     cm_SkipIoctlPath(ioctlp);
2454
2455     tp = ioctlp->inDatap;
2456
2457     /* ticket length */
2458     memcpy(&ticketLen, tp, sizeof(ticketLen));
2459     tp += sizeof(ticketLen);
2460     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
2461         return CM_ERROR_INVAL;
2462
2463     /* remember ticket and skip over it for now */
2464     ticket = tp;
2465     tp += ticketLen;
2466
2467     /* clear token size */
2468     memcpy(&ctSize, tp, sizeof(ctSize));
2469     tp += sizeof(ctSize);
2470     if (ctSize != sizeof(struct ClearToken))
2471         return CM_ERROR_INVAL;
2472
2473     /* clear token */
2474     memcpy(&ct, tp, ctSize);
2475     tp += ctSize;
2476     if (ct.AuthHandle == -1)
2477         ct.AuthHandle = 999;    /* more rxvab compat stuff */
2478
2479     /* more stuff, if any */
2480     if (ioctlp->inCopied > tp - saveDataPtr) {
2481         /* flags:  logon flag */
2482         memcpy(&flags, tp, sizeof(int));
2483         tp += sizeof(int);
2484
2485         /* cell name */
2486         cellp = cm_GetCell(tp, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
2487         if (!cellp) 
2488             return CM_ERROR_NOSUCHCELL;
2489         tp += strlen(tp) + 1;
2490
2491         /* user name */
2492         uname = tp;
2493         tp += strlen(tp) + 1;
2494
2495         if (flags & PIOCTL_LOGON) {
2496             /* SMB user name with which to associate tokens */
2497             smbname = tp;
2498             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
2499                      osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
2500             fprintf(stderr, "SMB name = %s\n", smbname);
2501             tp += strlen(tp) + 1;
2502         } else {
2503             osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
2504                      osi_LogSaveString(smb_logp, uname));
2505         }
2506
2507                 /* uuid */
2508         memcpy(&uuid, tp, sizeof(uuid));
2509         if (!cm_FindTokenEvent(uuid, sessionKey))
2510             return CM_ERROR_INVAL;
2511     } else {
2512         cellp = cm_data.rootCellp;
2513         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
2514     }
2515
2516     if (flags & PIOCTL_LOGON) {
2517         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
2518                                      SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
2519         release_userp = 1;
2520     }
2521
2522     /* store the token */
2523     lock_ObtainMutex(&userp->mx);
2524     ucellp = cm_GetUCell(userp, cellp);
2525     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
2526     ucellp->ticketLen = ticketLen;
2527     if (ucellp->ticketp)
2528         free(ucellp->ticketp);  /* Discard old token if any */
2529     ucellp->ticketp = malloc(ticketLen);
2530     memcpy(ucellp->ticketp, ticket, ticketLen);
2531     /*
2532      * Get the session key from the RPC, rather than from the pioctl.
2533      */
2534     /*
2535     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2536     */
2537     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
2538     ucellp->kvno = ct.AuthHandle;
2539     ucellp->expirationTime = ct.EndTimestamp;
2540     ucellp->gen++;
2541 #ifdef QUERY_AFSID
2542     ucellp->uid = ANONYMOUSID;
2543 #endif
2544     if (uname) {
2545         StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
2546 #ifdef QUERY_AFSID
2547         cm_UsernameToId(uname, ucellp, &ucellp->uid);
2548 #endif
2549     }
2550     ucellp->flags |= CM_UCELLFLAG_RXKAD;
2551     lock_ReleaseMutex(&userp->mx);
2552
2553     if (flags & PIOCTL_LOGON) {
2554         ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
2555     }
2556
2557     cm_ResetACLCache(userp);
2558
2559     if (release_userp)
2560         cm_ReleaseUser(userp);
2561
2562     return 0;
2563 }
2564
2565 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
2566 {
2567     char *tp, *cp;
2568     int iterator;
2569     int temp;
2570     cm_ucell_t *ucellp;
2571     struct ClearToken ct;
2572
2573     cm_SkipIoctlPath(ioctlp);
2574
2575     tp = ioctlp->inDatap;
2576     cp = ioctlp->outDatap;
2577
2578     /* iterator */
2579     memcpy(&iterator, tp, sizeof(iterator));
2580     tp += sizeof(iterator);
2581
2582     lock_ObtainMutex(&userp->mx);
2583
2584     /* look for token */
2585     for (;;iterator++) {
2586         ucellp = cm_FindUCell(userp, iterator);
2587         if (!ucellp) {
2588             lock_ReleaseMutex(&userp->mx);
2589             return CM_ERROR_NOMORETOKENS;
2590         }
2591         if (ucellp->flags & CM_UCELLFLAG_RXKAD)
2592             break;
2593     }       
2594
2595     /* new iterator */
2596     temp = ucellp->iterator + 1;
2597     memcpy(cp, &temp, sizeof(temp));
2598     cp += sizeof(temp);
2599
2600     /* ticket length */
2601     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2602     cp += sizeof(ucellp->ticketLen);
2603
2604     /* ticket */
2605     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2606     cp += ucellp->ticketLen;
2607
2608     /* clear token size */
2609     temp = sizeof(ct);
2610     memcpy(cp, &temp, sizeof(temp));
2611     cp += sizeof(temp);
2612
2613     /* clear token */
2614     ct.AuthHandle = ucellp->kvno;
2615     /*
2616      * Don't give out a real session key here
2617      */
2618     /*
2619     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2620     */
2621     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2622     ct.ViceId = 37;                     /* XXX */
2623     ct.BeginTimestamp = 0;              /* XXX */
2624     ct.EndTimestamp = ucellp->expirationTime;
2625     memcpy(cp, &ct, sizeof(ct));
2626     cp += sizeof(ct);
2627
2628     /* Primary flag (unused) */
2629     temp = 0;
2630     memcpy(cp, &temp, sizeof(temp));
2631     cp += sizeof(temp);
2632
2633     /* cell name */
2634     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2635     cp += strlen(cp) + 1;
2636
2637     /* user name */
2638     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2639     cp += strlen(cp) + 1;
2640
2641     ioctlp->outDatap = cp;
2642
2643     lock_ReleaseMutex(&userp->mx);
2644
2645     return 0;
2646 }
2647
2648 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2649 {
2650     char *cp;
2651     int temp;
2652     cm_cell_t *cellp;
2653     cm_ucell_t *ucellp;
2654     struct ClearToken ct;
2655     char *tp;
2656     afs_uuid_t uuid;
2657     cm_SkipIoctlPath(ioctlp);
2658
2659     tp = ioctlp->inDatap;
2660
2661     cp = ioctlp->outDatap;
2662
2663     /* cell name is right here */
2664     cellp = cm_GetCell(tp, 0);
2665     if (!cellp) 
2666         return CM_ERROR_NOSUCHCELL;
2667     tp += strlen(tp) + 1;
2668
2669     /* uuid */
2670     memcpy(&uuid, tp, sizeof(uuid));
2671
2672     lock_ObtainMutex(&userp->mx);
2673
2674     ucellp = cm_GetUCell(userp, cellp);
2675     if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2676         lock_ReleaseMutex(&userp->mx);
2677         return CM_ERROR_NOMORETOKENS;
2678     }
2679
2680     /* ticket length */
2681     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2682     cp += sizeof(ucellp->ticketLen);
2683
2684     /* ticket */
2685     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2686     cp += ucellp->ticketLen;
2687
2688     /* clear token size */
2689     temp = sizeof(ct);
2690     memcpy(cp, &temp, sizeof(temp));
2691     cp += sizeof(temp);
2692
2693     /* clear token */
2694     ct.AuthHandle = ucellp->kvno;
2695     /*
2696      * Don't give out a real session key here
2697      */
2698     /*
2699     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2700     */
2701     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2702     ct.ViceId = 37;                     /* XXX */
2703     ct.BeginTimestamp = 0;              /* XXX */
2704     ct.EndTimestamp = ucellp->expirationTime;
2705     memcpy(cp, &ct, sizeof(ct));
2706     cp += sizeof(ct);
2707
2708     /* Primary flag (unused) */
2709     temp = 0;
2710     memcpy(cp, &temp, sizeof(temp));
2711     cp += sizeof(temp);
2712
2713     /* cell name */
2714     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2715     cp += strlen(cp) + 1;
2716
2717     /* user name */
2718     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2719     cp += strlen(cp) + 1;
2720
2721     ioctlp->outDatap = cp;
2722
2723     lock_ReleaseMutex(&userp->mx);
2724
2725     cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2726
2727     return 0;
2728 }
2729
2730 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2731 {
2732     char *cp;
2733     cm_cell_t *cellp;
2734     cm_ucell_t *ucellp;
2735
2736     cm_SkipIoctlPath(ioctlp);
2737
2738     cp = ioctlp->outDatap;
2739
2740     /* cell name is right here */
2741     cellp = cm_GetCell(ioctlp->inDatap, 0);
2742     if (!cellp) 
2743         return CM_ERROR_NOSUCHCELL;
2744
2745     lock_ObtainMutex(&userp->mx);
2746
2747     ucellp = cm_GetUCell(userp, cellp);
2748     if (!ucellp) {
2749         lock_ReleaseMutex(&userp->mx);
2750         return CM_ERROR_NOMORETOKENS;
2751     }
2752
2753     osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2754
2755     if (ucellp->ticketp) {
2756         free(ucellp->ticketp);
2757         ucellp->ticketp = NULL;
2758     }
2759     ucellp->ticketLen = 0;
2760     memset(ucellp->sessionKey.data, 0, 8);
2761     ucellp->kvno = 0;
2762     ucellp->expirationTime = 0;
2763     ucellp->userName[0] = '\0';
2764     ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2765     ucellp->gen++;
2766
2767     lock_ReleaseMutex(&userp->mx);
2768
2769     cm_ResetACLCache(userp);
2770
2771     return 0;
2772 }
2773
2774 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2775 {
2776     cm_ucell_t *ucellp;
2777
2778     lock_ObtainMutex(&userp->mx);
2779
2780     for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2781         osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2782
2783         if (ucellp->ticketp) {
2784             free(ucellp->ticketp);
2785             ucellp->ticketp = NULL;
2786         }
2787         ucellp->ticketLen = 0;
2788         memset(ucellp->sessionKey.data, 0, 8);
2789         ucellp->kvno = 0;
2790         ucellp->expirationTime = 0;
2791         ucellp->userName[0] = '\0';
2792         ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2793         ucellp->gen++;
2794     }
2795
2796     lock_ReleaseMutex(&userp->mx);
2797
2798     cm_ResetACLCache(userp);
2799
2800     return 0;
2801 }
2802
2803 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2804 {
2805     char afspath[MAX_PATH];
2806     char *submountreqp;
2807     int nextAutoSubmount;
2808     HKEY hkSubmounts;
2809     DWORD dwType, dwSize;
2810     DWORD status;
2811     DWORD dwIndex;
2812     DWORD dwSubmounts;
2813
2814     cm_SkipIoctlPath(ioctlp);
2815
2816     /* Serialize this one, to prevent simultaneous mods
2817      * to afsdsbmt.ini
2818      */
2819     lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2820
2821     /* Parse the input parameters--first the required afs path,
2822      * then the requested submount name (which may be "").
2823      */
2824     cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2825     submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2826
2827     /* If the caller supplied a suggested submount name, see if
2828      * that submount name is in use... if so, the submount's path
2829      * has to match our path.
2830      */
2831
2832     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
2833                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2834                     0, 
2835                     "AFS", 
2836                     REG_OPTION_NON_VOLATILE,
2837                     KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2838                     NULL, 
2839                     &hkSubmounts,
2840                     NULL );
2841
2842     if (submountreqp && *submountreqp) {
2843         char submountPathNormalized[MAX_PATH];
2844         char submountPath[MAX_PATH];
2845
2846         dwSize = sizeof(submountPath);
2847         status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2848                                   &dwType, submountPath, &dwSize);
2849
2850         if (status != ERROR_SUCCESS) {
2851
2852             /* The suggested submount name isn't in use now--
2853              * so we can safely map the requested submount name
2854              * to the supplied path. Remember not to write the
2855              * leading "/afs" when writing out the submount.
2856              */
2857             RegSetValueEx( hkSubmounts, submountreqp, 0,
2858                            REG_EXPAND_SZ, 
2859                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2860                            &afspath[strlen(cm_mountRoot)]:"/",
2861                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2862                            (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2863
2864             RegCloseKey( hkSubmounts );
2865             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2866             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2867             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2868             return 0;
2869         }
2870
2871         /* The suggested submount name is already in use--if the
2872          * supplied path matches the submount's path, we can still
2873          * use the suggested submount name.
2874          */
2875         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2876         if (!strcmp (submountPathNormalized, afspath)) {
2877             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2878             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2879             RegCloseKey( hkSubmounts );
2880             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2881             return 0;
2882         }
2883     }
2884
2885     RegQueryInfoKey( hkSubmounts,
2886                      NULL,  /* lpClass */
2887                      NULL,  /* lpcClass */
2888                      NULL,  /* lpReserved */
2889                      NULL,  /* lpcSubKeys */
2890                      NULL,  /* lpcMaxSubKeyLen */
2891                      NULL,  /* lpcMaxClassLen */
2892                      &dwSubmounts, /* lpcValues */
2893                      NULL,  /* lpcMaxValueNameLen */
2894                      NULL,  /* lpcMaxValueLen */
2895                      NULL,  /* lpcbSecurityDescriptor */
2896                      NULL   /* lpftLastWriteTime */
2897                      );
2898
2899
2900     /* Having obtained a list of all available submounts, start
2901      * searching that list for a path which matches the requested
2902      * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2903      * submount, in case we need to add a new one later.
2904      */
2905
2906     nextAutoSubmount = 1;
2907
2908     for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2909         char submountPathNormalized[MAX_PATH];
2910         char submountPath[MAX_PATH] = "";
2911         DWORD submountPathLen = sizeof(submountPath);
2912         char submountName[MAX_PATH];
2913         DWORD submountNameLen = sizeof(submountName);
2914
2915         dwType = 0;
2916         RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2917                       &dwType, submountPath, &submountPathLen);
2918         if (dwType == REG_EXPAND_SZ) {
2919             char buf[MAX_PATH];
2920             StringCbCopyA(buf, MAX_PATH, submountPath);
2921             submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2922             if (submountPathLen > MAX_PATH)
2923                 continue;
2924         }
2925
2926         /* If this is an Auto### submount, remember its ### value */
2927         if ((!strnicmp (submountName, "auto", 4)) &&
2928              (isdigit (submountName[strlen("auto")]))) {
2929             int thisAutoSubmount;
2930             thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2931             nextAutoSubmount = max (nextAutoSubmount,
2932                                      thisAutoSubmount+1);
2933         }       
2934
2935         if ((submountPathLen == 0) ||
2936              (submountPathLen == sizeof(submountPath) - 1)) {
2937             continue;
2938         }
2939
2940         /* See if the path for this submount matches the path
2941          * that our caller specified. If so, we can return
2942          * this submount.
2943          */
2944         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2945         if (!strcmp (submountPathNormalized, afspath)) {
2946             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
2947             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2948             RegCloseKey(hkSubmounts);
2949             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2950             return 0;
2951
2952         }
2953     }
2954
2955     /* We've been through the entire list of existing submounts, and
2956      * didn't find any which matched the specified path. So, we'll
2957      * just have to add one. Remember not to write the leading "/afs"
2958      * when writing out the submount.
2959      */
2960
2961     StringCbPrintfA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "auto%ld", nextAutoSubmount);
2962
2963     RegSetValueEx( hkSubmounts, 
2964                    ioctlp->outDatap,
2965                    0,
2966                    REG_EXPAND_SZ, 
2967                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2968                    &afspath[strlen(cm_mountRoot)]:"/",
2969                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2970                    (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2971
2972     ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2973     RegCloseKey(hkSubmounts);
2974     lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2975     return 0;
2976 }
2977
2978 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2979 {
2980     memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2981     ioctlp->outDatap += sizeof(cryptall);
2982
2983     return 0;
2984 }
2985
2986 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2987 {
2988     afs_int32 c = cryptall;
2989
2990     cm_SkipIoctlPath(ioctlp);
2991
2992     memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2993
2994     if (c != cryptall) {
2995         if (cryptall)
2996             LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
2997         else
2998             LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
2999     }
3000     return 0;
3001 }
3002
3003 long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
3004 {
3005     afs_int32 flags;
3006     int code = 0;
3007
3008     cm_SkipIoctlPath(ioctlp);
3009
3010     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
3011     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3012         return -1;
3013     }
3014     if (flags & AFSCALL_RXSTATS_ENABLE) {
3015         rx_enableProcessRPCStats();
3016     }
3017     if (flags & AFSCALL_RXSTATS_DISABLE) {
3018         rx_disableProcessRPCStats();
3019     }
3020     if (flags & AFSCALL_RXSTATS_CLEAR) {
3021         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3022     }
3023     return 0;
3024 }
3025
3026 long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
3027 {
3028     afs_int32 flags;
3029     int code = 0;
3030
3031     cm_SkipIoctlPath(ioctlp);
3032
3033     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
3034     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3035         return -1;
3036     }
3037     if (flags & AFSCALL_RXSTATS_ENABLE) {
3038         rx_enablePeerRPCStats();
3039     }
3040     if (flags & AFSCALL_RXSTATS_DISABLE) {
3041         rx_disablePeerRPCStats();
3042     }
3043     if (flags & AFSCALL_RXSTATS_CLEAR) {
3044         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3045     }
3046     return 0;
3047 }
3048
3049 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
3050 {
3051   smb_user_t *uidp = ioctlp->uidp;
3052
3053   if (uidp && uidp->unp) {
3054     memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
3055     ioctlp->outDatap += strlen(uidp->unp->name);
3056   }
3057
3058   return 0;
3059 }
3060
3061 long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp)
3062 {
3063     long result = 0;
3064 #ifdef SMB_UNICODE
3065     long cmd;
3066
3067     cm_SkipIoctlPath(ioctlp);
3068
3069     memcpy(&cmd, ioctlp->inDatap, sizeof(long));
3070
3071     if (cmd & 2) {
3072         /* Setting the Unicode flag */
3073         LONG newflag;
3074
3075         newflag = ((cmd & 1) == 1);
3076
3077         InterlockedExchange(&smb_UseUnicode, newflag);
3078     }
3079
3080     result = smb_UseUnicode;
3081 #else
3082     result = 2;
3083 #endif
3084
3085     memcpy(ioctlp->outDatap, &result, sizeof(result));
3086     ioctlp->outDatap += sizeof(result);
3087
3088     return 0;
3089 }
3090
3091 long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
3092 {
3093     long cmd;
3094     afsUUID uuid;
3095
3096     cm_SkipIoctlPath(ioctlp);
3097
3098     memcpy(&cmd, ioctlp->inDatap, sizeof(long));
3099
3100     if (cmd) {             /* generate a new UUID */
3101         UuidCreate((UUID *) &uuid);
3102         cm_data.Uuid = uuid;
3103         cm_ForceNewConnectionsAllServers();
3104     }
3105
3106     memcpy(ioctlp->outDatap, &cm_data.Uuid, sizeof(cm_data.Uuid));
3107     ioctlp->outDatap += sizeof(cm_data.Uuid);
3108
3109     return 0;
3110 }
3111
3112
3113
3114 /* 
3115  * functions to dump contents of various structures. 
3116  * In debug build (linked with crt debug library) will dump allocated but not freed memory
3117  */
3118 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
3119 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
3120 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
3121
3122 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
3123 {
3124     long inValue = 0;
3125     HANDLE hLogFile;
3126     char logfileName[MAX_PATH+1];
3127     char *cookie;
3128     DWORD dwSize;
3129   
3130 #ifdef _DEBUG  
3131     static _CrtMemState memstate;
3132 #endif
3133   
3134     cm_SkipIoctlPath(ioctlp);
3135     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
3136   
3137     dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
3138     if ( dwSize == 0 || dwSize > sizeof(logfileName) )
3139     {
3140         GetWindowsDirectory(logfileName, sizeof(logfileName));
3141     }
3142     strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
3143
3144     hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3145   
3146     if (!hLogFile)
3147     {
3148       /* error */
3149       inValue = -1;
3150       memcpy(ioctlp->outDatap, &inValue, sizeof(long));
3151       ioctlp->outDatap += sizeof(long);
3152       
3153       return 0;               
3154     }
3155   
3156     SetFilePointer(hLogFile, 0, NULL, FILE_END);
3157   
3158     cookie = inValue ? "b" : "e";
3159   
3160 #ifdef _DEBUG  
3161   
3162     if (inValue)
3163     {
3164       _CrtMemCheckpoint(&memstate);           
3165     }
3166     else
3167     {
3168         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3169         _CrtSetReportFile(_CRT_WARN, hLogFile);
3170         _CrtMemDumpAllObjectsSince(&memstate);
3171     }
3172 #endif
3173   
3174     /* dump all interesting data */
3175     cm_MemDumpDirStats(hLogFile, cookie, 1);
3176     cm_MemDumpBPlusStats(hLogFile, cookie, 1);
3177     cm_DumpCells(hLogFile, cookie, 1);
3178     cm_DumpVolumes(hLogFile, cookie, 1);
3179     cm_DumpSCache(hLogFile, cookie, 1);
3180     cm_DumpBufHashTable(hLogFile, cookie, 1);
3181     smb_DumpVCP(hLogFile, cookie, 1);
3182
3183     CloseHandle(hLogFile);                          
3184   
3185     inValue = 0;        /* success */
3186     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
3187     ioctlp->outDatap += sizeof(long);
3188   
3189     return 0;
3190 }
3191
3192
3193 static long 
3194 cm_CheckServersStatus(cm_serverRef_t *serversp)
3195 {
3196     long code = 0;
3197     cm_serverRef_t *tsrp;
3198     cm_server_t *tsp;
3199     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
3200
3201     if (serversp == NULL) {
3202         osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", CM_ERROR_ALLDOWN);
3203         return CM_ERROR_ALLDOWN;
3204     }
3205
3206     lock_ObtainRead(&cm_serverLock);
3207     for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
3208         if (tsp = tsrp->server) {
3209             cm_GetServerNoLock(tsp);
3210             lock_ReleaseRead(&cm_serverLock);
3211             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
3212                 allDown = 0;
3213                 if (tsrp->status == srv_busy) {
3214                     allOffline = 0;
3215                     someBusy = 1;
3216                 } else if (tsrp->status == srv_offline) {
3217                     allBusy = 0;
3218                     someOffline = 1;
3219                 } else {
3220                     allOffline = 0;
3221                     allBusy = 0;
3222                     cm_PutServer(tsp);
3223                     goto done;
3224                 }
3225             }
3226             lock_ObtainRead(&cm_serverLock);
3227             cm_PutServerNoLock(tsp);
3228         }
3229     }   
3230     lock_ReleaseRead(&cm_serverLock);
3231
3232     if (allDown) 
3233         code = CM_ERROR_ALLDOWN;
3234     else if (allBusy) 
3235         code = CM_ERROR_ALLBUSY;
3236     else if (allOffline || (someBusy && someOffline))
3237         code = CM_ERROR_ALLOFFLINE;
3238
3239   done:
3240     osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", code);
3241     return code;
3242 }
3243
3244
3245 long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
3246 {
3247     long code;
3248     cm_scache_t *scp;
3249     cm_cell_t *cellp;
3250     cm_volume_t *tvp;
3251     cm_vol_state_t *statep;
3252     afs_uint32 volume;
3253     cm_req_t req;
3254     cm_ioctlQueryOptions_t *optionsp;
3255     afs_uint32 flags = 0;
3256
3257     cm_InitReq(&req);
3258
3259     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
3260     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
3261         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
3262
3263     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
3264         cm_fid_t fid;
3265         cm_SkipIoctlPath(ioctlp);
3266         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
3267                   optionsp->fid.vnode, optionsp->fid.unique);
3268         code = cm_GetSCache(&fid, &scp, userp, &req);
3269     } else {
3270         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
3271     }
3272     if (code) 
3273         return code;
3274         
3275 #ifdef AFS_FREELANCE_CLIENT
3276     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
3277         code = 0;
3278         cm_ReleaseSCache(scp);
3279     } else
3280 #endif
3281     {
3282         volume = scp->fid.volume;
3283
3284         cellp = cm_FindCellByID(scp->fid.cell, 0);
3285
3286         cm_ReleaseSCache(scp);
3287
3288         if (!cellp)
3289             return CM_ERROR_NOSUCHCELL;
3290
3291         code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
3292         if (code) 
3293             return code;
3294         
3295         statep = cm_VolumeStateByID(tvp, volume);
3296         switch (statep->state) {
3297         case vl_online:
3298         case vl_unknown:
3299             code = 0;
3300             break;
3301         case vl_busy:
3302             code = CM_ERROR_ALLBUSY;
3303             break;
3304         case vl_offline:
3305             code = CM_ERROR_ALLOFFLINE;
3306             break;
3307         case vl_alldown:
3308             code = CM_ERROR_ALLDOWN;
3309             break;
3310         }
3311         cm_PutVolume(tvp);
3312     }
3313     return code;
3314 }       
3315
3316
3317 long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
3318 {
3319     long code;
3320     cm_cell_t *cellp = NULL;
3321     cm_volume_t *volp;
3322     cm_vol_state_t *statep;
3323     struct VolStatTest * testp;
3324     cm_req_t req;
3325     afs_uint32 n;
3326
3327     cm_InitReq(&req);
3328
3329     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
3330     testp = (struct VolStatTest *)ioctlp->inDatap;
3331
3332 #ifdef AFS_FREELANCE_CLIENT
3333     if (testp->fid.cell == -1) 
3334         return CM_ERROR_NOACCESS;
3335 #endif
3336
3337     if (testp->flags & VOLSTAT_TEST_CHECK_VOLUME) {
3338         cm_CheckOfflineVolumes();
3339         return 0;
3340     }
3341
3342     if (testp->flags & VOLSTAT_TEST_NETWORK_UP) {
3343         cm_VolStatus_Network_Started(cm_NetbiosName
3344 #ifdef _WIN64
3345                                   , cm_NetbiosName
3346 #endif
3347                                   );
3348         return 0;
3349     }
3350
3351     if (testp->flags & VOLSTAT_TEST_NETWORK_DOWN) {
3352         cm_VolStatus_Network_Stopped(cm_NetbiosName
3353 #ifdef _WIN64
3354                                   , cm_NetbiosName
3355 #endif
3356                                   );
3357         return 0;
3358     }
3359
3360     if (testp->cellname[0]) {
3361         n = atoi(testp->cellname);
3362         if (n)
3363             testp->fid.cell = n;
3364         else
3365             cellp = cm_GetCell(testp->cellname, 0);
3366     }
3367
3368     if (testp->fid.cell > 0) {
3369         cellp = cm_FindCellByID(testp->fid.cell, 0);
3370     }
3371
3372     if (!cellp)
3373         return CM_ERROR_NOSUCHCELL;
3374
3375     if (testp->volname[0]) {
3376         n = atoi(testp->volname);
3377         if (n)
3378             testp->fid.volume = n;
3379         else
3380             code = cm_FindVolumeByName(cellp, testp->volname, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3381     }
3382
3383     if (testp->fid.volume > 0)
3384         code = cm_FindVolumeByID(cellp, testp->fid.volume, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3385
3386     if (code)
3387         return code;
3388         
3389     if (testp->fid.volume)
3390         statep = cm_VolumeStateByID(volp, testp->fid.volume);
3391     else
3392         statep = cm_VolumeStateByName(volp, testp->volname);
3393
3394     if (statep) {
3395         statep->state = testp->state;
3396         code = cm_VolStatus_Change_Notification(cellp->cellID, statep->ID, testp->state);
3397     }
3398
3399     cm_PutVolume(volp);
3400
3401     return code;
3402 }       
3403
3404