2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
12 #include <afs/cellconfig.h>
13 #include <afs/ptserver.h>
27 #include "afsd_init.h"
28 #include <WINNT\afsreg.h>
38 #include <..\afsrdr\kif.h>
45 /* Copied from afs_tokens.h */
46 #define PIOCTL_LOGON 0x1
49 osi_mutex_t cm_Afsdsbmt_Lock;
51 extern afs_int32 cryptall;
52 extern char cm_NetbiosName[];
54 extern void afsi_log(char *pattern, ...);
56 afs_uint32 cm_pioctlFollowMountPoint = 0;
58 void cm_InitIoctl(void)
60 lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
63 long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
67 lock_ObtainWrite(&scp->bufCreateLock);
68 code = buf_CleanVnode(scp, userp, reqp);
70 lock_ObtainMutex(&scp->mx);
71 cm_DiscardSCache(scp);
72 lock_ReleaseMutex(&scp->mx);
74 lock_ReleaseWrite(&scp->bufCreateLock);
75 osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
79 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
83 #ifdef AFS_FREELANCE_CLIENT
84 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
85 cm_noteLocalMountPointChange();
90 lock_ObtainWrite(&scp->bufCreateLock);
91 code = buf_FlushCleanPages(scp, userp, reqp);
93 lock_ObtainMutex(&scp->mx);
94 cm_DiscardSCache(scp);
96 lock_ReleaseMutex(&scp->mx);
98 lock_ReleaseWrite(&scp->bufCreateLock);
99 osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
103 long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
108 pscp = cm_FindSCacheParent(scp);
110 /* now flush the file */
111 code = cm_FlushFile(pscp, userp, reqp);
112 cm_ReleaseSCache(pscp);
118 long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
124 #ifdef AFS_FREELANCE_CLIENT
125 if ( cell == AFS_FAKE_ROOT_CELL_ID && volume == AFS_FAKE_ROOT_VOL_ID ) {
126 cm_noteLocalMountPointChange();
131 lock_ObtainWrite(&cm_scacheLock);
132 for (i=0; i<cm_data.scacheHashTableSize; i++) {
133 for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
134 if (scp->fid.volume == volume && scp->fid.cell == cell) {
135 cm_HoldSCacheNoLock(scp);
136 lock_ReleaseWrite(&cm_scacheLock);
138 /* now flush the file */
139 code = cm_FlushFile(scp, userp, reqp);
140 lock_ObtainWrite(&cm_scacheLock);
141 cm_ReleaseSCacheNoLock(scp);
145 lock_ReleaseWrite(&cm_scacheLock);
151 * cm_ResetACLCache -- invalidate ACL info for a user that has just
152 * obtained or lost tokens
154 void cm_ResetACLCache(cm_user_t *userp)
159 lock_ObtainWrite(&cm_scacheLock);
160 for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
161 for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
162 cm_HoldSCacheNoLock(scp);
163 lock_ReleaseWrite(&cm_scacheLock);
164 lock_ObtainMutex(&scp->mx);
165 cm_InvalidateACLUser(scp, userp);
166 lock_ReleaseMutex(&scp->mx);
167 lock_ObtainWrite(&cm_scacheLock);
168 cm_ReleaseSCacheNoLock(scp);
171 lock_ReleaseWrite(&cm_scacheLock);
175 * TranslateExtendedChars - This is a fix for TR 54482.
177 * If an extended character (80 - FF) is entered into a file
178 * or directory name in Windows, the character is translated
179 * into the OEM character map before being passed to us. Why
180 * this occurs is unknown. Our pioctl functions must match
181 * this translation for paths given via our own commands (like
182 * fs). If we do not do this, then we will try to perform an
183 * operation on a non-translated path, which we will fail to
184 * find, since the path was created with the translated chars.
185 * This function performs the required translation.
187 void TranslateExtendedChars(char *str)
195 /* parse the passed-in file name and do a namei on it. If we fail,
196 * return an error code, otherwise return the vnode located in *scpp.
198 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
203 cm_scache_t *substRootp = NULL;
204 cm_scache_t *iscp = NULL;
207 char * lastComponent = NULL;
208 afs_uint32 follow = (cm_pioctlFollowMountPoint ? CM_FLAG_FOLLOW : CM_FLAG_NOMOUNTCHASE);
210 relativePath = ioctlp->inDatap;
211 /* setup the next data value for the caller to use */
212 ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
214 osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
216 /* This is usually the file name, but for StatMountPoint it is the path. */
217 /* ioctlp->inDatap can be either of the form:
220 * \\netbios-name\submount\path\.
221 * \\netbios-name\submount\path\file
223 TranslateExtendedChars(relativePath);
225 /* This is usually nothing, but for StatMountPoint it is the file name. */
226 TranslateExtendedChars(ioctlp->inDatap);
229 /* we have passed the whole path, including the afs prefix.
230 when the pioctl call is made, we perform an ioctl to afsrdr
231 and it returns the correct (full) path. therefore, there is
232 no drive letter, and the path is absolute. */
233 code = cm_NameI(cm_data.rootSCachep, relativePath,
235 userp, "", reqp, scpp);
238 osi_Log1(afsd_logp,"cm_ParseIoctlPath code 0x%x", code);
243 if (relativePath[0] == relativePath[1] &&
244 relativePath[1] == '\\' &&
245 !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName)))
251 /* We may have found a UNC path.
252 * If the first component is the NetbiosName,
253 * then throw out the second component (the submount)
254 * since it had better expand into the value of ioctl->tidPathp
257 p = relativePath + 2 + strlen(cm_NetbiosName) + 1; /* buffer overflow vuln.? */
258 if ( !_strnicmp("all", p, 3) )
261 for (i = 0; *p && *p != '\\'; i++,p++ ) {
264 p++; /* skip past trailing slash */
265 shareName[i] = 0; /* terminate string */
267 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
269 /* we found a sharename, therefore use the resulting path */
270 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
271 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
272 userp, sharePath, reqp, &substRootp);
275 osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
279 lastComponent = strrchr(p, '\\');
280 if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
281 *lastComponent = '\0';
284 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
285 userp, NULL, reqp, &iscp);
287 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
288 userp, NULL, reqp, scpp);
290 cm_ReleaseSCache(iscp);
292 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
293 userp, NULL, reqp, scpp);
295 cm_ReleaseSCache(substRootp);
297 osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
301 /* otherwise, treat the name as a cellname mounted off the afs root.
302 * This requires that we reconstruct the shareName string with
303 * leading and trailing slashes.
305 p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
306 if ( !_strnicmp("all", p, 3) )
310 for (i = 1; *p && *p != '\\'; i++,p++ ) {
313 p++; /* skip past trailing slash */
314 shareName[i++] = '/'; /* add trailing slash */
315 shareName[i] = 0; /* terminate string */
318 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
319 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
320 userp, shareName, reqp, &substRootp);
322 osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
326 lastComponent = strrchr(p, '\\');
327 if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
328 *lastComponent = '\0';
331 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
332 userp, NULL, reqp, &iscp);
334 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
335 userp, NULL, reqp, scpp);
337 cm_ReleaseSCache(iscp);
339 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
340 userp, NULL, reqp, scpp);
344 cm_ReleaseSCache(substRootp);
345 osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
350 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
351 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
352 userp, ioctlp->tidPathp, reqp, &substRootp);
354 osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
358 lastComponent = strrchr(relativePath, '\\');
359 if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
360 *lastComponent = '\0';
363 code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
364 userp, NULL, reqp, &iscp);
366 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
367 userp, NULL, reqp, scpp);
369 cm_ReleaseSCache(iscp);
371 code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD,
372 userp, NULL, reqp, scpp);
375 cm_ReleaseSCache(substRootp);
376 osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
383 cm_ReleaseSCache(substRootp);
385 /* and return success */
386 osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
390 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
394 temp = (long) strlen(ioctlp->inDatap) + 1;
395 ioctlp->inDatap += temp;
399 /* format the specified path to look like "/afs/<cellname>/usr", by
400 * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
401 * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
402 * intentionally returned as "/afs/"--this makes submount manipulation
403 * easier (because we can always jump past the initial "/afs" to find
404 * the AFS path that should be written into afsdsbmt.ini).
406 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
409 char bslash_mountRoot[256];
411 strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
412 bslash_mountRoot[0] = '\\';
414 if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
415 StringCbCopy(outpathp, outlen, inpathp);
416 else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
417 StringCbCopy(outpathp, outlen, inpathp);
418 else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
419 StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
420 else // inpathp looks like "<cell>/usr"
421 StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
423 for (cp = outpathp; *cp != 0; ++cp) {
428 if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
429 outpathp[strlen(outpathp)-1] = 0;
432 if (!strcmpi (outpathp, cm_mountRoot)) {
433 StringCbCopy(outpathp, outlen, cm_mountRoot);
437 #define LEAF_SIZE 256
438 /* parse the passed-in file name and do a namei on its parent. If we fail,
439 * return an error code, otherwise return the vnode located in *scpp.
441 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
442 cm_scache_t **scpp, char *leafp)
447 cm_scache_t *substRootp = NULL;
449 StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
450 tp = strrchr(tbuffer, '\\');
451 jp = strrchr(tbuffer, '/');
454 else if (jp && (tp - tbuffer) < (jp - tbuffer))
457 StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
459 StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
464 StringCbCopyA(leafp, LEAF_SIZE, tp+1);
467 if (tbuffer[0] == tbuffer[1] &&
468 tbuffer[1] == '\\' &&
469 !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName)))
475 /* We may have found a UNC path.
476 * If the first component is the NetbiosName,
477 * then throw out the second component (the submount)
478 * since it had better expand into the value of ioctl->tidPathp
481 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
482 if ( !_strnicmp("all", p, 3) )
485 for (i = 0; *p && *p != '\\'; i++,p++ ) {
488 p++; /* skip past trailing slash */
489 shareName[i] = 0; /* terminate string */
491 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
493 /* we found a sharename, therefore use the resulting path */
494 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
495 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
496 userp, sharePath, reqp, &substRootp);
498 if (code) return code;
500 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
501 userp, NULL, reqp, scpp);
502 cm_ReleaseSCache(substRootp);
503 if (code) return code;
505 /* otherwise, treat the name as a cellname mounted off the afs root.
506 * This requires that we reconstruct the shareName string with
507 * leading and trailing slashes.
509 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
510 if ( !_strnicmp("all", p, 3) )
514 for (i = 1; *p && *p != '\\'; i++,p++ ) {
517 p++; /* skip past trailing slash */
518 shareName[i++] = '/'; /* add trailing slash */
519 shareName[i] = 0; /* terminate string */
521 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
522 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
523 userp, shareName, reqp, &substRootp);
524 if (code) return code;
526 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
527 userp, NULL, reqp, scpp);
528 cm_ReleaseSCache(substRootp);
529 if (code) return code;
532 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
533 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
534 userp, ioctlp->tidPathp, reqp, &substRootp);
535 if (code) return code;
537 code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
538 userp, NULL, reqp, scpp);
539 cm_ReleaseSCache(substRootp);
540 if (code) return code;
543 /* # of bytes of path */
544 code = (long)strlen(ioctlp->inDatap) + 1;
545 ioctlp->inDatap += code;
547 /* and return success */
551 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
556 AFSFetchStatus fileStatus;
562 struct rx_connection * callp;
566 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
567 if (code) return code;
569 /* now make the get acl call */
570 #ifdef AFS_FREELANCE_CLIENT
571 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
573 ioctlp->outDatap[0] ='\0';
577 fid.Volume = scp->fid.volume;
578 fid.Vnode = scp->fid.vnode;
579 fid.Unique = scp->fid.unique;
581 acl.AFSOpaque_val = ioctlp->outDatap;
582 acl.AFSOpaque_len = 0;
583 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
586 callp = cm_GetRxConn(connp);
587 code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
588 rx_PutConnection(callp);
590 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
591 code = cm_MapRPCError(code, &req);
592 cm_ReleaseSCache(scp);
594 if (code) return code;
596 /* skip over return data */
597 tlen = (int)strlen(ioctlp->outDatap) + 1;
598 ioctlp->outDatap += tlen;
600 /* and return success */
604 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
613 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
614 if (code) return code;
616 #ifdef AFS_FREELANCE_CLIENT
617 if ( cm_freelanceEnabled &&
618 scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
619 scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
620 scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
621 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
622 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
625 #endif /* AFS_FREELANCE_CLIENT */
627 cellp = cm_FindCellByID(scp->fid.cell, CM_FLAG_NOPROBE);
629 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
630 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
634 code = CM_ERROR_NOSUCHCELL;
637 cm_ReleaseSCache(scp);
641 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
646 AFSFetchStatus fileStatus;
651 struct rx_connection * callp;
655 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
656 if (code) return code;
658 #ifdef AFS_FREELANCE_CLIENT
659 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
660 code = CM_ERROR_NOACCESS;
664 /* now make the get acl call */
665 fid.Volume = scp->fid.volume;
666 fid.Vnode = scp->fid.vnode;
667 fid.Unique = scp->fid.unique;
669 acl.AFSOpaque_val = ioctlp->inDatap;
670 acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
671 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
674 callp = cm_GetRxConn(connp);
675 code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
676 rx_PutConnection(callp);
678 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
679 code = cm_MapRPCError(code, &req);
681 /* invalidate cache info, since we just trashed the ACL cache */
682 lock_ObtainMutex(&scp->mx);
683 cm_DiscardSCache(scp);
684 lock_ReleaseMutex(&scp->mx);
686 cm_ReleaseSCache(scp);
693 long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
702 lock_ObtainWrite(&cm_scacheLock);
703 for (i=0; i<cm_data.scacheHashTableSize; i++) {
704 for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
705 cm_HoldSCacheNoLock(scp);
706 lock_ReleaseWrite(&cm_scacheLock);
708 /* now flush the file */
709 code = cm_FlushFile(scp, userp, &req);
710 lock_ObtainWrite(&cm_scacheLock);
711 cm_ReleaseSCacheNoLock(scp);
714 lock_ReleaseWrite(&cm_scacheLock);
719 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
723 unsigned long volume;
729 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
730 if (code) return code;
732 #ifdef AFS_FREELANCE_CLIENT
733 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
734 code = CM_ERROR_NOACCESS;
738 volume = scp->fid.volume;
739 cell = scp->fid.cell;
740 cm_ReleaseSCache(scp);
742 code = cm_FlushVolume(userp, &req, cell, volume);
747 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
755 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
756 if (code) return code;
758 #ifdef AFS_FREELANCE_CLIENT
759 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
760 code = CM_ERROR_NOACCESS;
764 cm_FlushFile(scp, userp, &req);
766 cm_ReleaseSCache(scp);
771 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
775 char offLineMsg[256];
779 AFSFetchVolumeStatus volStat;
780 AFSStoreVolumeStatus storeStat;
785 struct rx_connection * callp;
789 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
790 if (code) return code;
792 #ifdef AFS_FREELANCE_CLIENT
793 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
794 code = CM_ERROR_NOACCESS;
798 cellp = cm_FindCellByID(scp->fid.cell, 0);
799 osi_assertx(cellp, "null cm_cell_t");
801 if (scp->flags & CM_SCACHEFLAG_RO) {
802 cm_ReleaseSCache(scp);
803 return CM_ERROR_READONLY;
806 code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req,
807 CM_GETVOL_FLAG_CREATE, &tvp);
809 cm_ReleaseSCache(scp);
814 /* Copy the junk out, using cp as a roving pointer. */
815 cp = ioctlp->inDatap;
816 memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
817 cp += sizeof(AFSFetchVolumeStatus);
818 StringCbCopyA(volName, sizeof(volName), cp);
819 cp += strlen(volName)+1;
820 StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
821 cp += strlen(offLineMsg)+1;
822 StringCbCopyA(motd, sizeof(motd), cp);
824 if (volStat.MinQuota != -1) {
825 storeStat.MinQuota = volStat.MinQuota;
826 storeStat.Mask |= AFS_SETMINQUOTA;
828 if (volStat.MaxQuota != -1) {
829 storeStat.MaxQuota = volStat.MaxQuota;
830 storeStat.Mask |= AFS_SETMAXQUOTA;
834 code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
837 callp = cm_GetRxConn(tcp);
838 code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
839 &storeStat, volName, offLineMsg, motd);
840 rx_PutConnection(callp);
842 } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
843 code = cm_MapRPCError(code, &req);
846 /* return on failure */
847 cm_ReleaseSCache(scp);
852 /* we are sending parms back to make compat. with prev system. should
853 * change interface later to not ask for current status, just set
856 cp = ioctlp->outDatap;
857 memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
858 cp += sizeof(VolumeStatus);
859 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
860 cp += strlen(volName)+1;
861 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
862 cp += strlen(offLineMsg)+1;
863 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
864 cp += strlen(motd)+1;
866 /* now return updated return data pointer */
867 ioctlp->outDatap = cp;
872 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
876 char offLineMsg[256];
880 AFSFetchVolumeStatus volStat;
886 struct rx_connection * callp;
890 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
891 if (code) return code;
893 #ifdef AFS_FREELANCE_CLIENT
894 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
896 strncpy(volName, "Freelance.Local.Root", sizeof(volName));
897 offLineMsg[0] = '\0';
898 strncpy(motd, "Freelance mode in use.", sizeof(motd));
899 volStat.Vid = scp->fid.volume;
900 volStat.MaxQuota = 0;
901 volStat.BlocksInUse = 100;
902 volStat.PartBlocksAvail = 0;
903 volStat.PartMaxBlocks = 100;
908 OfflineMsg = offLineMsg;
911 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
914 callp = cm_GetRxConn(connp);
915 code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
916 &volStat, &Name, &OfflineMsg, &MOTD);
917 rx_PutConnection(callp);
919 } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
920 code = cm_MapRPCError(code, &req);
923 cm_ReleaseSCache(scp);
924 if (code) return code;
926 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
927 cp = ioctlp->outDatap;
928 memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
929 cp += sizeof(AFSFetchVolumeStatus);
930 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
931 cp += strlen(volName)+1;
932 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
933 cp += strlen(offLineMsg)+1;
934 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
935 cp += strlen(motd)+1;
937 /* return new size */
938 ioctlp->outDatap = cp;
943 long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
953 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
954 if (code) return code;
956 memset(&fid, 0, sizeof(cm_fid_t));
957 fid.volume = scp->fid.volume;
958 fid.vnode = scp->fid.vnode;
959 fid.unique = scp->fid.unique;
961 cm_ReleaseSCache(scp);
963 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
964 cp = ioctlp->outDatap;
965 memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
966 cp += sizeof(cm_fid_t);
968 /* return new size */
969 ioctlp->outDatap = cp;
974 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
983 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
984 if (code) return code;
986 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
987 cp = ioctlp->outDatap;
988 memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
989 cp += sizeof(afs_uint32);
990 memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
991 cp += sizeof(afs_uint32);
993 /* return new size */
994 ioctlp->outDatap = cp;
996 cm_ReleaseSCache(scp);
1001 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1007 cm_serverRef_t **tsrpp, *current;
1009 unsigned long volume;
1015 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
1016 if (code) return code;
1018 volume = scp->fid.volume;
1020 cellp = cm_FindCellByID(scp->fid.cell, 0);
1022 cm_ReleaseSCache(scp);
1025 return CM_ERROR_NOSUCHCELL;
1027 code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
1031 cp = ioctlp->outDatap;
1033 lock_ObtainMutex(&tvp->mx);
1034 tsrpp = cm_GetVolServers(tvp, volume);
1035 lock_ObtainRead(&cm_serverLock);
1036 for (current = *tsrpp; current; current = current->next) {
1037 tsp = current->server;
1038 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1041 lock_ReleaseRead(&cm_serverLock);
1042 cm_FreeServerList(tsrpp, 0);
1043 lock_ReleaseMutex(&tvp->mx);
1045 /* still room for terminating NULL, add it on */
1046 volume = 0; /* reuse vbl */
1047 memcpy(cp, (char *)&volume, sizeof(long));
1050 ioctlp->outDatap = cp;
1055 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1065 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1066 if (code) return code;
1068 cp = ioctlp->inDatap;
1070 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1071 cm_ReleaseSCache(dscp);
1072 if (code) return code;
1074 lock_ObtainMutex(&scp->mx);
1076 /* now check that this is a real mount point */
1077 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1078 lock_ReleaseMutex(&scp->mx);
1079 cm_ReleaseSCache(scp);
1080 return CM_ERROR_INVAL;
1083 code = cm_ReadMountPoint(scp, userp, &req);
1085 cp = ioctlp->outDatap;
1086 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1087 cp += strlen(cp) + 1;
1088 ioctlp->outDatap = cp;
1090 lock_ReleaseMutex(&scp->mx);
1091 cm_ReleaseSCache(scp);
1096 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1106 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1107 if (code) return code;
1109 cp = ioctlp->inDatap;
1111 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1113 /* if something went wrong, bail out now */
1118 lock_ObtainMutex(&scp->mx);
1119 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1120 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1122 lock_ReleaseMutex(&scp->mx);
1123 cm_ReleaseSCache(scp);
1127 /* now check that this is a real mount point */
1128 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1129 lock_ReleaseMutex(&scp->mx);
1130 cm_ReleaseSCache(scp);
1131 code = CM_ERROR_INVAL;
1135 /* time to make the RPC, so drop the lock */
1136 lock_ReleaseMutex(&scp->mx);
1137 cm_ReleaseSCache(scp);
1139 /* easier to do it this way */
1140 code = cm_Unlink(dscp, cp, userp, &req);
1141 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1142 smb_NotifyChange(FILE_ACTION_REMOVED,
1143 FILE_NOTIFY_CHANGE_DIR_NAME,
1144 dscp, cp, NULL, TRUE);
1147 lock_ObtainMutex(&scp->mx);
1148 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1149 lock_ReleaseMutex(&scp->mx);
1152 cm_ReleaseSCache(dscp);
1156 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1166 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1167 tp = ioctlp->inDatap;
1170 memcpy(&temp, tp, sizeof(temp));
1171 if (temp == 0x12345678) { /* For afs3.3 version */
1172 memcpy(&csi, tp, sizeof(csi));
1173 if (csi.tinterval >= 0) {
1174 cp = ioctlp->outDatap;
1175 memcpy(cp, (char *)&cm_daemonCheckDownInterval, sizeof(long));
1176 ioctlp->outDatap += sizeof(long);
1177 if (csi.tinterval > 0) {
1178 if (!smb_SUser(userp))
1179 return CM_ERROR_NOACCESS;
1180 cm_daemonCheckDownInterval = csi.tinterval;
1188 } else { /* For pre afs3.3 versions */
1189 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1190 ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
1191 if (cp - ioctlp->inAllocp < ioctlp->inCopied) /* still more data available */
1196 * 1: fast check, don't contact servers.
1197 * 2: local cell only.
1200 /* have cell name, too */
1201 cellp = cm_GetCell(cp, (temp & 1) ? CM_FLAG_NOPROBE : 0);
1203 return CM_ERROR_NOSUCHCELL;
1205 else cellp = (cm_cell_t *) 0;
1206 if (!cellp && (temp & 2)) {
1207 /* use local cell */
1208 cellp = cm_FindCellByID(1, 0);
1210 if (!(temp & 1)) { /* if not fast, call server checker routine */
1211 /* check down servers */
1212 cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
1216 /* now return the current down server list */
1217 cp = ioctlp->outDatap;
1218 lock_ObtainRead(&cm_serverLock);
1219 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
1220 if (cellp && tsp->cellp != cellp) continue; /* cell spec'd and wrong */
1221 if ((tsp->flags & CM_SERVERFLAG_DOWN)
1222 && tsp->type == CM_SERVER_FILE) {
1223 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1227 lock_ReleaseRead(&cm_serverLock);
1229 ioctlp->outDatap = cp;
1233 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1235 /* we don't print anything superfluous, so we don't support the gag call */
1236 return CM_ERROR_INVAL;
1239 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1241 cm_RefreshVolumes();
1245 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1250 cm_SkipIoctlPath(ioctlp);
1252 memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1254 temp = cm_data.buf_nOrigBuffers;
1256 /* temp is in 1K units, convert to # of buffers */
1257 temp = temp / (cm_data.buf_blockSize / 1024);
1260 /* now adjust the cache size */
1261 code = buf_SetNBuffers(temp);
1266 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1270 cm_SkipIoctlPath(ioctlp);
1272 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1276 afsd_ForceTrace(FALSE);
1277 buf_ForceTrace(FALSE);
1281 /* set tracing value to low order bit */
1282 if ((inValue & 1) == 0) {
1283 /* disable tracing */
1284 osi_LogDisable(afsd_logp);
1285 rx_DebugOnOff(FALSE);
1288 /* enable tracing */
1289 osi_LogEnable(afsd_logp);
1290 rx_DebugOnOff(TRUE);
1294 /* see if we're supposed to do a reset, too */
1296 osi_LogReset(afsd_logp);
1299 /* and copy out tracing flag */
1300 inValue = afsd_logp->enabled; /* use as a temp vbl */
1301 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1302 ioctlp->outDatap += sizeof(long);
1306 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1308 cm_cacheParms_t parms;
1310 memset(&parms, 0, sizeof(parms));
1312 /* first we get, in 1K units, the cache size */
1313 parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1315 /* and then the actual # of buffers in use (not in the free list, I guess,
1316 * will be what we do).
1318 parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1320 memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1321 ioctlp->outDatap += sizeof(parms);
1326 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1331 cm_serverRef_t *serverRefp;
1332 cm_server_t *serverp;
1338 cm_SkipIoctlPath(ioctlp);
1340 tp = ioctlp->inDatap;
1342 memcpy((char *)&whichCell, tp, sizeof(long));
1345 /* see if more than one long passed in, ignoring the null pathname (the -1) */
1346 if (ioctlp->inCopied-1 > sizeof(long)) {
1347 memcpy((char *)&magic, tp, sizeof(long));
1350 lock_ObtainRead(&cm_cellLock);
1351 for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
1352 if (whichCell == 0) break;
1355 lock_ReleaseRead(&cm_cellLock);
1359 cp = ioctlp->outDatap;
1361 if (magic == 0x12345678) {
1362 memcpy(cp, (char *)&magic, sizeof(long));
1365 memset(cp, 0, max * sizeof(long));
1367 lock_ObtainRead(&cm_serverLock); /* for going down server list */
1368 /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1369 serverRefp = tcellp->vlServersp;
1370 for (i=0; i<max; i++) {
1371 if (!serverRefp) break;
1372 serverp = serverRefp->server;
1373 memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1375 serverRefp = serverRefp->next;
1377 lock_ReleaseRead(&cm_serverLock);
1378 cp = basep + max * sizeof(afs_int32);
1379 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
1380 cp += strlen(tcellp->name)+1;
1381 ioctlp->outDatap = cp;
1387 return CM_ERROR_NOMORETOKENS; /* mapped to EDOM */
1390 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1392 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1394 /* NT cache manager will read cell information from CellServDB each time
1395 * cell is accessed. So, this call is necessary only if list of server for a cell
1396 * changes (or IP addresses of cell servers changes).
1397 * All that needs to be done is to refresh server information for all cells that
1398 * are already loaded.
1400 * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1405 cm_SkipIoctlPath(ioctlp);
1406 lock_ObtainWrite(&cm_cellLock);
1408 for (cp = cm_data.allCellsp; cp; cp=cp->allNextp)
1411 lock_ObtainMutex(&cp->mx);
1412 /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1413 cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
1414 cp->vlServersp = NULL;
1415 code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1416 #ifdef AFS_AFSDB_ENV
1418 if (cm_dnsEnabled) {
1420 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1421 if ( code == 0 ) { /* got cell from DNS */
1422 cp->flags |= CM_CELLFLAG_DNS;
1423 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1424 cp->timeout = time(0) + ttl;
1429 cp->flags &= ~CM_CELLFLAG_DNS;
1431 #endif /* AFS_AFSDB_ENV */
1433 cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1436 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1437 cm_RandomizeServer(&cp->vlServersp);
1439 lock_ReleaseMutex(&cp->mx);
1442 lock_ReleaseWrite(&cm_cellLock);
1446 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1450 if (cm_freelanceEnabled) {
1451 if (cm_GetRootCellName(ioctlp->outDatap))
1452 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
1453 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1454 } else if (cm_data.rootCellp) {
1455 /* return the default cellname to the caller */
1456 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
1457 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1459 /* if we don't know our default cell, return failure */
1460 code = CM_ERROR_NOSUCHCELL;
1466 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1468 long setSysName, foundname = 0;
1469 char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1470 int t, count, num = 0;
1471 char **sysnamelist[MAXSYSNAME];
1473 cm_SkipIoctlPath(ioctlp);
1475 memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1476 ioctlp->inDatap += sizeof(long);
1480 if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1482 cp2 = ioctlp->inDatap;
1483 for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1484 /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1485 t = (int)strlen(cp);
1486 if (t >= MAXSYSNAME || t <= 0)
1488 /* check for names that can shoot us in the foot */
1489 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1495 /* inname gets first entry in case we're being a translator */
1496 /* (we are never a translator) */
1497 t = (int)strlen(ioctlp->inDatap);
1498 memcpy(inname, ioctlp->inDatap, t + 1);
1499 ioctlp->inDatap += t + 1;
1503 /* Not xlating, so local case */
1505 osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1507 if (!setSysName) { /* user just wants the info */
1508 StringCbCopyA(outname, sizeof(outname), cm_sysName);
1509 foundname = cm_sysNameCount;
1510 *sysnamelist = cm_sysNameList;
1512 /* Local guy; only root can change sysname */
1513 /* clear @sys entries from the dnlc, once afs_lookup can
1514 * do lookups of @sys entries and thinks it can trust them */
1515 /* privs ok, store the entry, ... */
1516 StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1517 StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1518 if (setSysName > 1) { /* ... or list */
1519 cp = ioctlp->inDatap;
1520 for (count = 1; count < setSysName; ++count) {
1521 if (!cm_sysNameList[count])
1522 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1523 __FILE__, __LINE__);
1524 t = (int)strlen(cp);
1525 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1529 cm_sysNameCount = setSysName;
1533 /* return the sysname to the caller */
1534 cp = ioctlp->outDatap;
1535 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1536 cp += sizeof(afs_int32); /* skip found flag */
1538 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
1539 cp += strlen(outname) + 1; /* skip name and terminating null char */
1540 for ( count=1; count < foundname ; ++count) { /* ... or list */
1541 if ( !(*sysnamelist)[count] )
1542 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n",
1543 __FILE__, __LINE__);
1544 t = (int)strlen((*sysnamelist)[count]);
1545 if (t >= MAXSYSNAME)
1546 osi_panic("cm_IoctlSysName: sysname entry garbled\n",
1547 __FILE__, __LINE__);
1548 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
1552 ioctlp->outDatap = cp;
1559 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1564 cm_SkipIoctlPath(ioctlp);
1566 cellp = cm_GetCell(ioctlp->inDatap, 0);
1568 return CM_ERROR_NOSUCHCELL;
1571 lock_ObtainMutex(&cellp->mx);
1572 if (cellp->flags & CM_CELLFLAG_SUID)
1573 temp |= CM_SETCELLFLAG_SUID;
1574 lock_ReleaseMutex(&cellp->mx);
1576 /* now copy out parm */
1577 memcpy(ioctlp->outDatap, &temp, sizeof(long));
1578 ioctlp->outDatap += sizeof(long);
1583 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1588 cm_SkipIoctlPath(ioctlp);
1590 cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1592 return CM_ERROR_NOSUCHCELL;
1594 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1596 lock_ObtainMutex(&cellp->mx);
1597 if (temp & CM_SETCELLFLAG_SUID)
1598 cellp->flags |= CM_CELLFLAG_SUID;
1600 cellp->flags &= ~CM_CELLFLAG_SUID;
1601 lock_ReleaseMutex(&cellp->mx);
1606 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1608 cm_SSetPref_t *spin; /* input */
1609 cm_SPref_t *srvin; /* one input component */
1611 int i, vlonly, noServers, type;
1612 struct sockaddr_in tmp;
1613 unsigned short rank;
1615 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1617 spin = (cm_SSetPref_t *)ioctlp->inDatap;
1618 noServers = spin->num_servers;
1619 vlonly = spin->flags;
1621 type = CM_SERVER_VLDB;
1623 type = CM_SERVER_FILE;
1625 for ( i=0; i < noServers; i++)
1627 srvin = &(spin->servers[i]);
1628 rank = srvin->rank + (rand() & 0x000f);
1629 tmp.sin_addr = srvin->host;
1630 tmp.sin_family = AF_INET;
1632 tsp = cm_FindServer(&tmp, type);
1633 if ( tsp ) /* an existing server - ref count increased */
1635 tsp->ipRank = rank; /* no need to protect by mutex*/
1637 if (type == CM_SERVER_FILE)
1639 /* find volumes which might have RO copy
1640 /* on server and change the ordering of
1643 cm_ChangeRankVolume(tsp);
1647 /* set preferences for an existing vlserver */
1648 cm_ChangeRankCellVLServer(tsp);
1651 else /* add a new server without a cell */
1653 tsp = cm_NewServer(&tmp, type, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
1656 lock_ObtainMutex(&tsp->mx);
1657 tsp->flags |= CM_SERVERFLAG_PREF_SET;
1658 lock_ReleaseMutex(&tsp->mx);
1659 cm_PutServer(tsp); /* decrease refcount */
1664 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1666 cm_SPrefRequest_t *spin; /* input */
1667 cm_SPrefInfo_t *spout; /* output */
1668 cm_SPref_t *srvout; /* one output component */
1670 int i, vlonly, noServers;
1672 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1674 spin = (cm_SPrefRequest_t *)ioctlp->inDatap;
1675 spout = (cm_SPrefInfo_t *) ioctlp->outDatap;
1676 srvout = spout->servers;
1677 noServers = spin->num_servers;
1678 vlonly = spin->flags & CM_SPREF_VLONLY;
1679 spout->num_servers = 0;
1681 lock_ObtainRead(&cm_serverLock); /* get server lock */
1683 for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1684 if (spin->offset > i) {
1685 continue; /* catch up to where we left off */
1688 if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1689 continue; /* ignore fileserver for -vlserver option*/
1690 if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1691 continue; /* ignore vlservers */
1693 srvout->host = tsp->addr.sin_addr;
1694 srvout->rank = tsp->ipRank;
1696 spout->num_servers++;
1699 lock_ReleaseRead(&cm_serverLock); /* release server lock */
1701 if ( tsp ) /* we ran out of space in the output buffer */
1702 spout->next_offset = i;
1704 spout->next_offset = 0;
1705 ioctlp->outDatap += sizeof(cm_SPrefInfo_t) +
1706 (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1710 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1712 /* we ignore default asynchrony since we only have one way
1713 * of doing this today.
1718 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1720 char leaf[LEAF_SIZE];
1734 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1738 /* Translate chars for the mount point name */
1739 TranslateExtendedChars(leaf);
1742 * The fs command allows the user to specify partial cell names on NT. These must
1743 * be expanded to the full cell name for mount points so that the mount points will
1744 * work on UNIX clients.
1747 /* Extract the possibly partial cell name */
1748 StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1); /* Skip the mp type character */
1750 if (cp = strchr(cell, ':')) {
1751 /* Extract the volume name */
1753 StringCbCopyA(volume, sizeof(volume), cp + 1);
1755 /* Get the full name for this cell */
1756 code = cm_SearchCellFile(cell, fullCell, 0, 0);
1757 #ifdef AFS_AFSDB_ENV
1758 if (code && cm_dnsEnabled)
1759 code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1762 cm_ReleaseSCache(dscp);
1763 return CM_ERROR_NOSUCHCELL;
1766 StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1768 /* No cell name specified */
1769 StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1772 #ifdef AFS_FREELANCE_CLIENT
1773 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1774 /* we are adding the mount point to the root dir., so call
1775 * the freelance code to do the add. */
1776 osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1777 code = cm_FreelanceAddMount(leaf, fullCell, volume,
1778 *ioctlp->inDatap == '%', NULL);
1779 cm_ReleaseSCache(dscp);
1783 /* create the symlink with mode 644. The lack of X bits tells
1784 * us that it is a mount point.
1786 tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1787 tattr.unixModeBits = 0644;
1788 tattr.clientModTime = time(NULL);
1790 code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1791 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1792 smb_NotifyChange(FILE_ACTION_ADDED,
1793 FILE_NOTIFY_CHANGE_DIR_NAME,
1794 dscp, leaf, NULL, TRUE);
1796 cm_ReleaseSCache(dscp);
1800 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1802 char leaf[LEAF_SIZE];
1811 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1812 if (code) return code;
1814 /* Translate chars for the link name */
1815 TranslateExtendedChars(leaf);
1817 /* Translate chars for the linked to name */
1818 TranslateExtendedChars(ioctlp->inDatap);
1820 cp = ioctlp->inDatap; /* contents of link */
1822 #ifdef AFS_FREELANCE_CLIENT
1823 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1824 /* we are adding the symlink to the root dir., so call
1825 * the freelance code to do the add. */
1826 if (cp[0] == cp[1] && cp[1] == '\\' &&
1827 !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName)))
1829 /* skip \\AFS\ or \\AFS\all\ */
1831 p = cp + 2 + strlen(cm_NetbiosName) + 1;
1832 if ( !_strnicmp("all", p, 3) )
1836 osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1837 code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1838 cm_ReleaseSCache(dscp);
1843 /* Create symlink with mode 0755. */
1844 tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1845 tattr.unixModeBits = 0755;
1847 code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1848 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1849 smb_NotifyChange(FILE_ACTION_ADDED,
1850 FILE_NOTIFY_CHANGE_FILE_NAME
1851 | FILE_NOTIFY_CHANGE_DIR_NAME,
1852 dscp, leaf, NULL, TRUE);
1854 cm_ReleaseSCache(dscp);
1860 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1867 cm_scache_t *newRootScp;
1872 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1873 if (code) return code;
1875 cp = ioctlp->inDatap;
1877 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1878 cm_ReleaseSCache(dscp);
1879 if (code) return code;
1881 /* Check that it's a real symlink */
1882 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1883 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1884 scp->fileType != CM_SCACHETYPE_INVALID) {
1885 cm_ReleaseSCache(scp);
1886 return CM_ERROR_INVAL;
1889 code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1890 cm_ReleaseSCache(scp);
1892 cp = ioctlp->outDatap;
1893 if (newRootScp != NULL) {
1894 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
1895 StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
1898 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
1899 cp += strlen(cp) + 1;
1900 ioctlp->outDatap = cp;
1901 cm_FreeSpace(spacep);
1902 if (newRootScp != NULL)
1903 cm_ReleaseSCache(newRootScp);
1905 } else if (code == CM_ERROR_PATH_NOT_COVERED &&
1906 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1907 code == CM_ERROR_NOSUCHPATH &&
1908 scp->fileType == CM_SCACHETYPE_INVALID) {
1910 cp = ioctlp->outDatap;
1911 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1912 cp += strlen(cp) + 1;
1913 ioctlp->outDatap = cp;
1920 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1921 {/*CHECK FOR VALID SYMLINK*/
1930 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1931 if (code) return code;
1933 cp = ioctlp->inDatap;
1934 osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1936 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1937 cm_ReleaseSCache(dscp);
1938 if (code) return code;
1940 /* Check that it's a real symlink */
1941 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1942 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1943 scp->fileType != CM_SCACHETYPE_INVALID)
1944 code = CM_ERROR_INVAL;
1945 cm_ReleaseSCache(scp);
1949 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1959 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1960 if (code) return code;
1962 cp = ioctlp->inDatap;
1964 #ifdef AFS_FREELANCE_CLIENT
1965 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1966 /* we are adding the mount point to the root dir., so call
1967 * the freelance code to do the add. */
1968 osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
1969 code = cm_FreelanceRemoveSymlink(cp);
1970 cm_ReleaseSCache(dscp);
1975 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1977 /* if something went wrong, bail out now */
1981 lock_ObtainMutex(&scp->mx);
1982 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1983 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1987 /* now check that this is a real symlink */
1988 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1989 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1990 scp->fileType != CM_SCACHETYPE_INVALID) {
1991 code = CM_ERROR_INVAL;
1995 /* time to make the RPC, so drop the lock */
1996 lock_ReleaseMutex(&scp->mx);
1998 /* easier to do it this way */
1999 code = cm_Unlink(dscp, cp, userp, &req);
2000 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2001 smb_NotifyChange(FILE_ACTION_REMOVED,
2002 FILE_NOTIFY_CHANGE_FILE_NAME
2003 | FILE_NOTIFY_CHANGE_DIR_NAME,
2004 dscp, cp, NULL, TRUE);
2006 lock_ObtainMutex(&scp->mx);
2008 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2011 lock_ReleaseMutex(&scp->mx);
2012 cm_ReleaseSCache(scp);
2015 cm_ReleaseSCache(dscp);
2020 long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
2025 static struct afsconf_cell info;
2026 struct rx_connection *serverconns[MAXSERVERS];
2027 struct rx_securityClass *sc[3];
2028 afs_int32 scIndex = 2; /* authenticated - we have a token */
2029 struct ubik_client *pruclient = NULL;
2030 struct afsconf_dir *tdir;
2034 tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
2035 code = afsconf_GetCellInfo(tdir, ucellp->cellp->name, "afsprot", &info);
2036 afsconf_Close(tdir);
2042 /* we have the token that was given to us in the settoken
2043 * call. we just have to use it.
2045 scIndex = 2; /* kerberos ticket */
2046 sc[2] = rxkad_NewClientSecurityObject(rxkad_clear, &ucellp->sessionKey,
2047 ucellp->kvno, ucellp->ticketLen,
2050 memset(serverconns, 0, sizeof(serverconns)); /* terminate list!!! */
2051 for (i = 0; i < info.numServers; i++)
2053 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
2054 info.hostAddr[i].sin_port, PRSRV, sc[scIndex],
2057 code = ubik_ClientInit(serverconns, &pruclient);
2062 code = rxs_Release(sc[scIndex]);
2064 lids.idlist_len = 0;
2065 lids.idlist_val = 0;
2066 lnames.namelist_len = 1;
2067 lnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
2068 strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
2069 lnames.namelist_val[0][PR_MAXNAMELEN-1] = '\0';
2070 for ( p=lnames.namelist_val[0], r=NULL; *p; p++ ) {
2076 if (r && !stricmp(r+1,ucellp->cellp->name))
2079 code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
2080 if (lids.idlist_val) {
2081 *uid = *lids.idlist_val;
2082 free(lids.idlist_val);
2084 if (lnames.namelist_val)
2085 free(lnames.namelist_val);
2088 ubik_ClientDestroy(pruclient);
2094 #endif /* QUERY_AFSID */
2096 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2103 struct ClearToken ct;
2113 int release_userp = 0;
2116 saveDataPtr = ioctlp->inDatap;
2118 cm_SkipIoctlPath(ioctlp);
2120 tp = ioctlp->inDatap;
2123 memcpy(&ticketLen, tp, sizeof(ticketLen));
2124 tp += sizeof(ticketLen);
2125 if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
2126 return CM_ERROR_INVAL;
2128 /* remember ticket and skip over it for now */
2132 /* clear token size */
2133 memcpy(&ctSize, tp, sizeof(ctSize));
2134 tp += sizeof(ctSize);
2135 if (ctSize != sizeof(struct ClearToken))
2136 return CM_ERROR_INVAL;
2139 memcpy(&ct, tp, ctSize);
2141 if (ct.AuthHandle == -1)
2142 ct.AuthHandle = 999; /* more rxvab compat stuff */
2144 /* more stuff, if any */
2145 if (ioctlp->inCopied > tp - saveDataPtr) {
2146 /* flags: logon flag */
2147 memcpy(&flags, tp, sizeof(int));
2151 cellp = cm_GetCell(tp, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
2153 return CM_ERROR_NOSUCHCELL;
2154 tp += strlen(tp) + 1;
2158 tp += strlen(tp) + 1;
2160 #ifndef AFSIFS /* no SMB username, so we cannot logon based on this */
2161 if (flags & PIOCTL_LOGON) {
2162 /* SMB user name with which to associate tokens */
2164 osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
2165 osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
2166 fprintf(stderr, "SMB name = %s\n", smbname);
2167 tp += strlen(tp) + 1;
2169 osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
2170 osi_LogSaveString(smb_logp, uname));
2175 memcpy(&uuid, tp, sizeof(uuid));
2176 if (!cm_FindTokenEvent(uuid, sessionKey))
2177 return CM_ERROR_INVAL;
2179 cellp = cm_data.rootCellp;
2180 osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
2184 if (flags & PIOCTL_LOGON) {
2185 userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
2186 SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
2191 /* store the token */
2192 lock_ObtainMutex(&userp->mx);
2193 ucellp = cm_GetUCell(userp, cellp);
2194 osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
2195 ucellp->ticketLen = ticketLen;
2196 if (ucellp->ticketp)
2197 free(ucellp->ticketp); /* Discard old token if any */
2198 ucellp->ticketp = malloc(ticketLen);
2199 memcpy(ucellp->ticketp, ticket, ticketLen);
2201 * Get the session key from the RPC, rather than from the pioctl.
2204 memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2206 memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
2207 ucellp->kvno = ct.AuthHandle;
2208 ucellp->expirationTime = ct.EndTimestamp;
2211 ucellp->uid = ANONYMOUSID;
2214 StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
2216 cm_UsernameToId(uname, ucellp, &ucellp->uid);
2219 ucellp->flags |= CM_UCELLFLAG_RXKAD;
2220 lock_ReleaseMutex(&userp->mx);
2222 if (flags & PIOCTL_LOGON) {
2223 ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
2226 cm_ResetACLCache(userp);
2229 cm_ReleaseUser(userp);
2234 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
2240 struct ClearToken ct;
2242 cm_SkipIoctlPath(ioctlp);
2244 tp = ioctlp->inDatap;
2245 cp = ioctlp->outDatap;
2248 memcpy(&iterator, tp, sizeof(iterator));
2249 tp += sizeof(iterator);
2251 lock_ObtainMutex(&userp->mx);
2253 /* look for token */
2254 for (;;iterator++) {
2255 ucellp = cm_FindUCell(userp, iterator);
2257 lock_ReleaseMutex(&userp->mx);
2258 return CM_ERROR_NOMORETOKENS;
2260 if (ucellp->flags & CM_UCELLFLAG_RXKAD)
2265 temp = ucellp->iterator + 1;
2266 memcpy(cp, &temp, sizeof(temp));
2270 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2271 cp += sizeof(ucellp->ticketLen);
2274 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2275 cp += ucellp->ticketLen;
2277 /* clear token size */
2279 memcpy(cp, &temp, sizeof(temp));
2283 ct.AuthHandle = ucellp->kvno;
2285 * Don't give out a real session key here
2288 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2290 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2291 ct.ViceId = 37; /* XXX */
2292 ct.BeginTimestamp = 0; /* XXX */
2293 ct.EndTimestamp = ucellp->expirationTime;
2294 memcpy(cp, &ct, sizeof(ct));
2297 /* Primary flag (unused) */
2299 memcpy(cp, &temp, sizeof(temp));
2303 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2304 cp += strlen(cp) + 1;
2307 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2308 cp += strlen(cp) + 1;
2310 ioctlp->outDatap = cp;
2312 lock_ReleaseMutex(&userp->mx);
2317 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2323 struct ClearToken ct;
2326 cm_SkipIoctlPath(ioctlp);
2328 tp = ioctlp->inDatap;
2330 cp = ioctlp->outDatap;
2332 /* cell name is right here */
2333 cellp = cm_GetCell(tp, 0);
2335 return CM_ERROR_NOSUCHCELL;
2336 tp += strlen(tp) + 1;
2339 memcpy(&uuid, tp, sizeof(uuid));
2341 lock_ObtainMutex(&userp->mx);
2343 ucellp = cm_GetUCell(userp, cellp);
2344 if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2345 lock_ReleaseMutex(&userp->mx);
2346 return CM_ERROR_NOMORETOKENS;
2350 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2351 cp += sizeof(ucellp->ticketLen);
2354 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2355 cp += ucellp->ticketLen;
2357 /* clear token size */
2359 memcpy(cp, &temp, sizeof(temp));
2363 ct.AuthHandle = ucellp->kvno;
2365 * Don't give out a real session key here
2368 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2370 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2371 ct.ViceId = 37; /* XXX */
2372 ct.BeginTimestamp = 0; /* XXX */
2373 ct.EndTimestamp = ucellp->expirationTime;
2374 memcpy(cp, &ct, sizeof(ct));
2377 /* Primary flag (unused) */
2379 memcpy(cp, &temp, sizeof(temp));
2383 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2384 cp += strlen(cp) + 1;
2387 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2388 cp += strlen(cp) + 1;
2390 ioctlp->outDatap = cp;
2392 lock_ReleaseMutex(&userp->mx);
2394 cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2399 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2405 cm_SkipIoctlPath(ioctlp);
2407 cp = ioctlp->outDatap;
2409 /* cell name is right here */
2410 cellp = cm_GetCell(ioctlp->inDatap, 0);
2412 return CM_ERROR_NOSUCHCELL;
2414 lock_ObtainMutex(&userp->mx);
2416 ucellp = cm_GetUCell(userp, cellp);
2418 lock_ReleaseMutex(&userp->mx);
2419 return CM_ERROR_NOMORETOKENS;
2422 osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2424 if (ucellp->ticketp) {
2425 free(ucellp->ticketp);
2426 ucellp->ticketp = NULL;
2428 ucellp->ticketLen = 0;
2429 memset(ucellp->sessionKey.data, 0, 8);
2431 ucellp->expirationTime = 0;
2432 ucellp->userName[0] = '\0';
2433 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2436 lock_ReleaseMutex(&userp->mx);
2438 cm_ResetACLCache(userp);
2443 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2447 lock_ObtainMutex(&userp->mx);
2449 for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2450 osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2452 if (ucellp->ticketp) {
2453 free(ucellp->ticketp);
2454 ucellp->ticketp = NULL;
2456 ucellp->ticketLen = 0;
2457 memset(ucellp->sessionKey.data, 0, 8);
2459 ucellp->expirationTime = 0;
2460 ucellp->userName[0] = '\0';
2461 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2465 lock_ReleaseMutex(&userp->mx);
2467 cm_ResetACLCache(userp);
2472 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2474 char afspath[MAX_PATH];
2476 int nextAutoSubmount;
2478 DWORD dwType, dwSize;
2483 cm_SkipIoctlPath(ioctlp);
2485 /* Serialize this one, to prevent simultaneous mods
2488 lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2490 /* Parse the input parameters--first the required afs path,
2491 * then the requested submount name (which may be "").
2493 cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2494 submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2496 /* If the caller supplied a suggested submount name, see if
2497 * that submount name is in use... if so, the submount's path
2498 * has to match our path.
2501 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2502 AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2505 REG_OPTION_NON_VOLATILE,
2506 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2511 if (submountreqp && *submountreqp) {
2512 char submountPathNormalized[MAX_PATH];
2513 char submountPath[MAX_PATH];
2515 dwSize = sizeof(submountPath);
2516 status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2517 &dwType, submountPath, &dwSize);
2519 if (status != ERROR_SUCCESS) {
2521 /* The suggested submount name isn't in use now--
2522 * so we can safely map the requested submount name
2523 * to the supplied path. Remember not to write the
2524 * leading "/afs" when writing out the submount.
2526 RegSetValueEx( hkSubmounts, submountreqp, 0,
2528 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2529 &afspath[strlen(cm_mountRoot)]:"/",
2530 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2531 (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2533 RegCloseKey( hkSubmounts );
2534 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2535 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2536 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2540 /* The suggested submount name is already in use--if the
2541 * supplied path matches the submount's path, we can still
2542 * use the suggested submount name.
2544 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2545 if (!strcmp (submountPathNormalized, afspath)) {
2546 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2547 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2548 RegCloseKey( hkSubmounts );
2549 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2554 RegQueryInfoKey( hkSubmounts,
2556 NULL, /* lpcClass */
2557 NULL, /* lpReserved */
2558 NULL, /* lpcSubKeys */
2559 NULL, /* lpcMaxSubKeyLen */
2560 NULL, /* lpcMaxClassLen */
2561 &dwSubmounts, /* lpcValues */
2562 NULL, /* lpcMaxValueNameLen */
2563 NULL, /* lpcMaxValueLen */
2564 NULL, /* lpcbSecurityDescriptor */
2565 NULL /* lpftLastWriteTime */
2569 /* Having obtained a list of all available submounts, start
2570 * searching that list for a path which matches the requested
2571 * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2572 * submount, in case we need to add a new one later.
2575 nextAutoSubmount = 1;
2577 for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2578 char submountPathNormalized[MAX_PATH];
2579 char submountPath[MAX_PATH] = "";
2580 DWORD submountPathLen = sizeof(submountPath);
2581 char submountName[MAX_PATH];
2582 DWORD submountNameLen = sizeof(submountName);
2585 RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2586 &dwType, submountPath, &submountPathLen);
2587 if (dwType == REG_EXPAND_SZ) {
2589 StringCbCopyA(buf, MAX_PATH, submountPath);
2590 submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2591 if (submountPathLen > MAX_PATH)
2595 /* If this is an Auto### submount, remember its ### value */
2596 if ((!strnicmp (submountName, "auto", 4)) &&
2597 (isdigit (submountName[strlen("auto")]))) {
2598 int thisAutoSubmount;
2599 thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2600 nextAutoSubmount = max (nextAutoSubmount,
2601 thisAutoSubmount+1);
2604 if ((submountPathLen == 0) ||
2605 (submountPathLen == sizeof(submountPath) - 1)) {
2609 /* See if the path for this submount matches the path
2610 * that our caller specified. If so, we can return
2613 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2614 if (!strcmp (submountPathNormalized, afspath)) {
2615 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
2616 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2617 RegCloseKey(hkSubmounts);
2618 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2624 /* We've been through the entire list of existing submounts, and
2625 * didn't find any which matched the specified path. So, we'll
2626 * just have to add one. Remember not to write the leading "/afs"
2627 * when writing out the submount.
2630 StringCbPrintfA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "auto%ld", nextAutoSubmount);
2632 RegSetValueEx( hkSubmounts,
2636 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2637 &afspath[strlen(cm_mountRoot)]:"/",
2638 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2639 (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2641 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2642 RegCloseKey(hkSubmounts);
2643 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2647 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2649 memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2650 ioctlp->outDatap += sizeof(cryptall);
2655 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2657 afs_int32 c = cryptall;
2659 cm_SkipIoctlPath(ioctlp);
2661 memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2663 if (c != cryptall) {
2665 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
2667 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
2672 long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
2677 cm_SkipIoctlPath(ioctlp);
2679 memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2680 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2683 if (flags & AFSCALL_RXSTATS_ENABLE) {
2684 rx_enableProcessRPCStats();
2686 if (flags & AFSCALL_RXSTATS_DISABLE) {
2687 rx_disableProcessRPCStats();
2689 if (flags & AFSCALL_RXSTATS_CLEAR) {
2690 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
2695 long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
2700 cm_SkipIoctlPath(ioctlp);
2702 memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2703 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2706 if (flags & AFSCALL_RXSTATS_ENABLE) {
2707 rx_enablePeerRPCStats();
2709 if (flags & AFSCALL_RXSTATS_DISABLE) {
2710 rx_disablePeerRPCStats();
2712 if (flags & AFSCALL_RXSTATS_CLEAR) {
2713 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
2718 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
2720 smb_user_t *uidp = ioctlp->uidp;
2722 if (uidp && uidp->unp) {
2723 memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
2724 ioctlp->outDatap += strlen(uidp->unp->name);
2730 long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
2735 memcpy(&cmd, ioctlp->inDatap, sizeof(long));
2737 if (cmd) { /* generate a new UUID */
2738 UuidCreate((UUID *) &uuid);
2739 cm_data.Uuid = uuid;
2740 cm_ForceNewConnectionsAllServers();
2743 memcpy(ioctlp->outDatap, &cm_data.Uuid, sizeof(cm_data.Uuid));
2744 ioctlp->outDatap += sizeof(cm_data.Uuid);
2750 * functions to dump contents of various structures.
2751 * In debug build (linked with crt debug library) will dump allocated but not freed memory
2753 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
2754 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
2755 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
2757 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
2761 char logfileName[MAX_PATH+1];
2766 static _CrtMemState memstate;
2769 cm_SkipIoctlPath(ioctlp);
2770 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
2772 dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
2773 if ( dwSize == 0 || dwSize > sizeof(logfileName) )
2775 GetWindowsDirectory(logfileName, sizeof(logfileName));
2777 strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
2779 hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2785 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2786 ioctlp->outDatap += sizeof(long);
2791 SetFilePointer(hLogFile, 0, NULL, FILE_END);
2793 cookie = inValue ? "b" : "e";
2799 _CrtMemCheckpoint(&memstate);
2803 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2804 _CrtSetReportFile(_CRT_WARN, hLogFile);
2805 _CrtMemDumpAllObjectsSince(&memstate);
2809 /* dump all interesting data */
2810 cm_MemDumpDirStats(hLogFile, cookie, 1);
2811 cm_MemDumpBPlusStats(hLogFile, cookie, 1);
2812 cm_DumpCells(hLogFile, cookie, 1);
2813 cm_DumpVolumes(hLogFile, cookie, 1);
2814 cm_DumpSCache(hLogFile, cookie, 1);
2815 cm_DumpBufHashTable(hLogFile, cookie, 1);
2816 smb_DumpVCP(hLogFile, cookie, 1);
2818 CloseHandle(hLogFile);
2820 inValue = 0; /* success */
2821 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2822 ioctlp->outDatap += sizeof(long);
2829 cm_CheckServersStatus(cm_serverRef_t *serversp)
2832 cm_serverRef_t *tsrp;
2834 int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
2836 if (serversp == NULL) {
2837 osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", CM_ERROR_ALLDOWN);
2838 return CM_ERROR_ALLDOWN;
2841 lock_ObtainRead(&cm_serverLock);
2842 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
2843 if (tsp = tsrp->server) {
2844 cm_GetServerNoLock(tsp);
2845 lock_ReleaseRead(&cm_serverLock);
2846 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
2848 if (tsrp->status == srv_busy) {
2851 } else if (tsrp->status == srv_offline) {
2861 lock_ObtainRead(&cm_serverLock);
2862 cm_PutServerNoLock(tsp);
2865 lock_ReleaseRead(&cm_serverLock);
2868 code = CM_ERROR_ALLDOWN;
2870 code = CM_ERROR_ALLBUSY;
2871 else if (allOffline || (someBusy && someOffline))
2872 code = CM_ERROR_ALLOFFLINE;
2875 osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", code);
2880 long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
2886 cm_vol_state_t *statep;
2892 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
2896 #ifdef AFS_FREELANCE_CLIENT
2897 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
2899 cm_ReleaseSCache(scp);
2903 volume = scp->fid.volume;
2905 cellp = cm_FindCellByID(scp->fid.cell, 0);
2907 cm_ReleaseSCache(scp);
2910 return CM_ERROR_NOSUCHCELL;
2912 code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
2916 if (volume == tvp->rw.ID)
2918 else if (volume == tvp->ro.ID)
2923 switch (statep->state) {
2929 code = CM_ERROR_ALLBUSY;
2932 code = CM_ERROR_ALLOFFLINE;
2935 code = CM_ERROR_ALLDOWN;
2944 long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
2947 cm_cell_t *cellp = NULL;
2949 cm_vol_state_t *statep;
2950 struct VolStatTest * testp;
2957 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
2958 testp = (struct VolStatTest *)ioctlp->inDatap;
2960 #ifdef AFS_FREELANCE_CLIENT
2961 if (testp->fid.cell == -1)
2962 return CM_ERROR_NOACCESS;
2965 if (testp->flags & VOLSTAT_TEST_CHECK_VOLUME) {
2966 cm_CheckOfflineVolumes();
2970 if (testp->flags & VOLSTAT_TEST_NETWORK_UP) {
2971 cm_VolStatus_Network_Started(cm_NetbiosName
2979 if (testp->flags & VOLSTAT_TEST_NETWORK_DOWN) {
2980 cm_VolStatus_Network_Stopped(cm_NetbiosName
2988 if (testp->cellname[0]) {
2989 n = atoi(testp->cellname);
2991 testp->fid.cell = n;
2993 cellp = cm_GetCell(testp->cellname, 0);
2996 if (testp->fid.cell > 0) {
2997 cellp = cm_FindCellByID(testp->fid.cell, 0);
3001 return CM_ERROR_NOSUCHCELL;
3003 if (testp->volname[0]) {
3004 n = atoi(testp->volname);
3006 testp->fid.volume = n;
3008 code = cm_GetVolumeByName(cellp, testp->volname, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3011 if (testp->fid.volume > 0)
3012 code = cm_GetVolumeByID(cellp, testp->fid.volume, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3017 if (testp->fid.volume) {
3018 if (testp->fid.volume == volp->rw.ID)
3020 else if (testp->fid.volume == volp->ro.ID)
3025 len = strlen(testp->volname);
3027 if (stricmp(".readonly", &testp->volname[len-9]) == 0)
3029 else if (stricmp(".backup", &testp->volname[len-7]) == 0)
3036 statep->state = testp->state;
3037 code = cm_VolStatus_Change_Notification(cellp->cellID, statep->ID, testp->state);