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>
19 #include <sys/socket.h>
31 #include "afsd_init.h"
32 #include <WINNT\afsreg.h>
47 #include <..\afsrdr\kif.h>
54 /* Copied from afs_tokens.h */
55 #define PIOCTL_LOGON 0x1
58 osi_mutex_t cm_Afsdsbmt_Lock;
60 extern afs_int32 cryptall;
61 extern char cm_NetbiosName[];
63 extern void afsi_log(char *pattern, ...);
65 void cm_InitIoctl(void)
67 lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
70 long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
74 lock_ObtainWrite(&scp->bufCreateLock);
75 code = buf_CleanVnode(scp, userp, reqp);
77 lock_ObtainMutex(&scp->mx);
78 cm_DiscardSCache(scp);
79 lock_ReleaseMutex(&scp->mx);
81 lock_ReleaseWrite(&scp->bufCreateLock);
82 osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
86 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
90 #ifdef AFS_FREELANCE_CLIENT
91 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
92 cm_noteLocalMountPointChange();
97 lock_ObtainWrite(&scp->bufCreateLock);
98 code = buf_FlushCleanPages(scp, userp, reqp);
100 lock_ObtainMutex(&scp->mx);
101 cm_DiscardSCache(scp);
103 lock_ReleaseMutex(&scp->mx);
105 lock_ReleaseWrite(&scp->bufCreateLock);
106 osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
110 long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
115 pscp = cm_FindSCacheParent(scp);
117 /* now flush the file */
118 code = cm_FlushFile(pscp, userp, reqp);
119 cm_ReleaseSCache(pscp);
125 long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
131 #ifdef AFS_FREELANCE_CLIENT
132 if ( cell == AFS_FAKE_ROOT_CELL_ID && volume == AFS_FAKE_ROOT_VOL_ID ) {
133 cm_noteLocalMountPointChange();
138 lock_ObtainWrite(&cm_scacheLock);
139 for (i=0; i<cm_data.scacheHashTableSize; i++) {
140 for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
141 if (scp->fid.volume == volume && scp->fid.cell == cell) {
142 cm_HoldSCacheNoLock(scp);
143 lock_ReleaseWrite(&cm_scacheLock);
145 /* now flush the file */
146 code = cm_FlushFile(scp, userp, reqp);
147 lock_ObtainWrite(&cm_scacheLock);
148 cm_ReleaseSCacheNoLock(scp);
152 lock_ReleaseWrite(&cm_scacheLock);
158 * cm_ResetACLCache -- invalidate ACL info for a user that has just
159 * obtained or lost tokens
161 void cm_ResetACLCache(cm_user_t *userp)
166 lock_ObtainWrite(&cm_scacheLock);
167 for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
168 for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
169 cm_HoldSCacheNoLock(scp);
170 lock_ReleaseWrite(&cm_scacheLock);
171 lock_ObtainMutex(&scp->mx);
172 cm_InvalidateACLUser(scp, userp);
173 lock_ReleaseMutex(&scp->mx);
174 lock_ObtainWrite(&cm_scacheLock);
175 cm_ReleaseSCacheNoLock(scp);
178 lock_ReleaseWrite(&cm_scacheLock);
182 * TranslateExtendedChars - This is a fix for TR 54482.
184 * If an extended character (80 - FF) is entered into a file
185 * or directory name in Windows, the character is translated
186 * into the OEM character map before being passed to us. Why
187 * this occurs is unknown. Our pioctl functions must match
188 * this translation for paths given via our own commands (like
189 * fs). If we do not do this, then we will try to perform an
190 * operation on a non-translated path, which we will fail to
191 * find, since the path was created with the translated chars.
192 * This function performs the required translation.
194 void TranslateExtendedChars(char *str)
207 while (*p) *p++ &= 0x7f; /* turn off high bit; probably not right */
211 /* parse the passed-in file name and do a namei on it. If we fail,
212 * return an error code, otherwise return the vnode located in *scpp.
214 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
219 cm_scache_t *substRootp = NULL;
220 cm_scache_t *iscp = NULL;
223 char * lastComponent = NULL;
224 afs_uint32 follow = 0;
226 relativePath = ioctlp->inDatap;
227 /* setup the next data value for the caller to use */
228 ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
230 osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
232 /* This is usually the file name, but for StatMountPoint it is the path. */
233 /* ioctlp->inDatap can be either of the form:
236 * \\netbios-name\submount\path\.
237 * \\netbios-name\submount\path\file
239 TranslateExtendedChars(relativePath);
241 /* This is usually nothing, but for StatMountPoint it is the file name. */
242 TranslateExtendedChars(ioctlp->inDatap);
245 /* we have passed the whole path, including the afs prefix.
246 when the pioctl call is made, we perform an ioctl to afsrdr
247 and it returns the correct (full) path. therefore, there is
248 no drive letter, and the path is absolute. */
249 code = cm_NameI(cm_data.rootSCachep, relativePath,
250 CM_FLAG_CASEFOLD | follow,
251 userp, "", reqp, scpp);
254 osi_Log1(afsd_logp,"cm_ParseIoctlPath code 0x%x", code);
259 if (relativePath[0] == relativePath[1] &&
260 relativePath[1] == '\\' &&
261 !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName)))
267 /* We may have found a UNC path.
268 * If the first component is the NetbiosName,
269 * then throw out the second component (the submount)
270 * since it had better expand into the value of ioctl->tidPathp
273 p = relativePath + 2 + strlen(cm_NetbiosName) + 1; /* buffer overflow vuln.? */
274 if ( !_strnicmp("all", p, 3) )
277 for (i = 0; *p && *p != '\\'; i++,p++ ) {
280 p++; /* skip past trailing slash */
281 shareName[i] = 0; /* terminate string */
283 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
285 /* we found a sharename, therefore use the resulting path */
286 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
287 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
288 userp, sharePath, reqp, &substRootp);
291 osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
295 lastComponent = strrchr(p, '\\');
296 if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
297 *lastComponent = '\0';
300 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
301 userp, NULL, reqp, &iscp);
303 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | CM_FLAG_NOMOUNTCHASE,
304 userp, NULL, reqp, scpp);
306 cm_ReleaseSCache(iscp);
308 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
309 userp, NULL, reqp, scpp);
311 cm_ReleaseSCache(substRootp);
313 osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
317 /* otherwise, treat the name as a cellname mounted off the afs root.
318 * This requires that we reconstruct the shareName string with
319 * leading and trailing slashes.
321 p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
322 if ( !_strnicmp("all", p, 3) )
326 for (i = 1; *p && *p != '\\'; i++,p++ ) {
329 p++; /* skip past trailing slash */
330 shareName[i++] = '/'; /* add trailing slash */
331 shareName[i] = 0; /* terminate string */
334 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
335 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
336 userp, shareName, reqp, &substRootp);
338 osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
342 lastComponent = strrchr(p, '\\');
343 if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
344 *lastComponent = '\0';
347 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
348 userp, NULL, reqp, &iscp);
350 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | CM_FLAG_NOMOUNTCHASE,
351 userp, NULL, reqp, scpp);
353 cm_ReleaseSCache(iscp);
355 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
356 userp, NULL, reqp, scpp);
360 cm_ReleaseSCache(substRootp);
361 osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
366 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
367 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
368 userp, ioctlp->tidPathp, reqp, &substRootp);
370 osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
374 lastComponent = strrchr(relativePath, '\\');
375 if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
376 *lastComponent = '\0';
379 code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
380 userp, NULL, reqp, &iscp);
382 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | CM_FLAG_NOMOUNTCHASE,
383 userp, NULL, reqp, scpp);
385 cm_ReleaseSCache(iscp);
387 code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD,
388 userp, NULL, reqp, scpp);
391 cm_ReleaseSCache(substRootp);
392 osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
399 cm_ReleaseSCache(substRootp);
401 /* and return success */
402 osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
406 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
410 temp = (long) strlen(ioctlp->inDatap) + 1;
411 ioctlp->inDatap += temp;
415 /* format the specified path to look like "/afs/<cellname>/usr", by
416 * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
417 * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
418 * intentionally returned as "/afs/"--this makes submount manipulation
419 * easier (because we can always jump past the initial "/afs" to find
420 * the AFS path that should be written into afsdsbmt.ini).
422 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
425 char bslash_mountRoot[256];
427 strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
428 bslash_mountRoot[0] = '\\';
430 if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
431 StringCbCopy(outpathp, outlen, inpathp);
432 else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
433 StringCbCopy(outpathp, outlen, inpathp);
434 else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
435 StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
436 else // inpathp looks like "<cell>/usr"
437 StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
439 for (cp = outpathp; *cp != 0; ++cp) {
444 if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
445 outpathp[strlen(outpathp)-1] = 0;
448 if (!strcmpi (outpathp, cm_mountRoot)) {
449 StringCbCopy(outpathp, outlen, cm_mountRoot);
453 #define LEAF_SIZE 256
454 /* parse the passed-in file name and do a namei on its parent. If we fail,
455 * return an error code, otherwise return the vnode located in *scpp.
457 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
458 cm_scache_t **scpp, char *leafp)
463 cm_scache_t *substRootp = NULL;
465 StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
466 tp = strrchr(tbuffer, '\\');
467 jp = strrchr(tbuffer, '/');
470 else if (jp && (tp - tbuffer) < (jp - tbuffer))
473 StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
475 StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
480 StringCbCopyA(leafp, LEAF_SIZE, tp+1);
483 if (tbuffer[0] == tbuffer[1] &&
484 tbuffer[1] == '\\' &&
485 !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName)))
491 /* We may have found a UNC path.
492 * If the first component is the NetbiosName,
493 * then throw out the second component (the submount)
494 * since it had better expand into the value of ioctl->tidPathp
497 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
498 if ( !_strnicmp("all", p, 3) )
501 for (i = 0; *p && *p != '\\'; i++,p++ ) {
504 p++; /* skip past trailing slash */
505 shareName[i] = 0; /* terminate string */
507 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
509 /* we found a sharename, therefore use the resulting path */
510 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
511 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
512 userp, sharePath, reqp, &substRootp);
514 if (code) return code;
516 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
517 userp, NULL, reqp, scpp);
518 cm_ReleaseSCache(substRootp);
519 if (code) return code;
521 /* otherwise, treat the name as a cellname mounted off the afs root.
522 * This requires that we reconstruct the shareName string with
523 * leading and trailing slashes.
525 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
526 if ( !_strnicmp("all", p, 3) )
530 for (i = 1; *p && *p != '\\'; i++,p++ ) {
533 p++; /* skip past trailing slash */
534 shareName[i++] = '/'; /* add trailing slash */
535 shareName[i] = 0; /* terminate string */
537 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
538 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
539 userp, shareName, reqp, &substRootp);
540 if (code) return code;
542 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
543 userp, NULL, reqp, scpp);
544 cm_ReleaseSCache(substRootp);
545 if (code) return code;
548 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
549 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
550 userp, ioctlp->tidPathp, reqp, &substRootp);
551 if (code) return code;
553 code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
554 userp, NULL, reqp, scpp);
555 cm_ReleaseSCache(substRootp);
556 if (code) return code;
559 /* # of bytes of path */
560 code = (long)strlen(ioctlp->inDatap) + 1;
561 ioctlp->inDatap += code;
563 /* and return success */
567 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
572 AFSFetchStatus fileStatus;
578 struct rx_connection * callp;
582 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
583 if (code) return code;
585 /* now make the get acl call */
586 #ifdef AFS_FREELANCE_CLIENT
587 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
589 ioctlp->outDatap[0] ='\0';
593 fid.Volume = scp->fid.volume;
594 fid.Vnode = scp->fid.vnode;
595 fid.Unique = scp->fid.unique;
597 acl.AFSOpaque_val = ioctlp->outDatap;
598 acl.AFSOpaque_len = 0;
599 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
602 callp = cm_GetRxConn(connp);
603 code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
604 rx_PutConnection(callp);
606 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
607 code = cm_MapRPCError(code, &req);
608 cm_ReleaseSCache(scp);
610 if (code) return code;
612 /* skip over return data */
613 tlen = (int)strlen(ioctlp->outDatap) + 1;
614 ioctlp->outDatap += tlen;
616 /* and return success */
620 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
629 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
630 if (code) return code;
632 #ifdef AFS_FREELANCE_CLIENT
633 if ( cm_freelanceEnabled &&
634 scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
635 scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
636 scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
637 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
638 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
641 #endif /* AFS_FREELANCE_CLIENT */
643 cellp = cm_FindCellByID(scp->fid.cell);
645 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
646 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
650 code = CM_ERROR_NOSUCHCELL;
653 cm_ReleaseSCache(scp);
657 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
662 AFSFetchStatus fileStatus;
667 struct rx_connection * callp;
671 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
672 if (code) return code;
674 #ifdef AFS_FREELANCE_CLIENT
675 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
676 code = CM_ERROR_NOACCESS;
680 /* now make the get acl call */
681 fid.Volume = scp->fid.volume;
682 fid.Vnode = scp->fid.vnode;
683 fid.Unique = scp->fid.unique;
685 acl.AFSOpaque_val = ioctlp->inDatap;
686 acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
687 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
690 callp = cm_GetRxConn(connp);
691 code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
692 rx_PutConnection(callp);
694 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
695 code = cm_MapRPCError(code, &req);
697 /* invalidate cache info, since we just trashed the ACL cache */
698 lock_ObtainMutex(&scp->mx);
699 cm_DiscardSCache(scp);
700 lock_ReleaseMutex(&scp->mx);
702 cm_ReleaseSCache(scp);
709 long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
718 lock_ObtainWrite(&cm_scacheLock);
719 for (i=0; i<cm_data.scacheHashTableSize; i++) {
720 for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
721 cm_HoldSCacheNoLock(scp);
722 lock_ReleaseWrite(&cm_scacheLock);
724 /* now flush the file */
725 code = cm_FlushFile(scp, userp, &req);
726 lock_ObtainWrite(&cm_scacheLock);
727 cm_ReleaseSCacheNoLock(scp);
730 lock_ReleaseWrite(&cm_scacheLock);
735 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
739 unsigned long volume;
745 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
746 if (code) return code;
748 #ifdef AFS_FREELANCE_CLIENT
749 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
750 code = CM_ERROR_NOACCESS;
754 volume = scp->fid.volume;
755 cell = scp->fid.cell;
756 cm_ReleaseSCache(scp);
758 code = cm_FlushVolume(userp, &req, cell, volume);
763 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
771 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
772 if (code) return code;
774 #ifdef AFS_FREELANCE_CLIENT
775 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
776 code = CM_ERROR_NOACCESS;
780 cm_FlushFile(scp, userp, &req);
782 cm_ReleaseSCache(scp);
787 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
791 char offLineMsg[256];
795 AFSFetchVolumeStatus volStat;
796 AFSStoreVolumeStatus storeStat;
801 struct rx_connection * callp;
805 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
806 if (code) return code;
808 #ifdef AFS_FREELANCE_CLIENT
809 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
810 code = CM_ERROR_NOACCESS;
814 cellp = cm_FindCellByID(scp->fid.cell);
815 osi_assertx(cellp, "null cm_cell_t");
817 if (scp->flags & CM_SCACHEFLAG_RO) {
818 cm_ReleaseSCache(scp);
819 return CM_ERROR_READONLY;
822 code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req,
823 CM_GETVOL_FLAG_CREATE, &tvp);
825 cm_ReleaseSCache(scp);
830 /* Copy the junk out, using cp as a roving pointer. */
831 cp = ioctlp->inDatap;
832 memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
833 cp += sizeof(AFSFetchVolumeStatus);
834 StringCbCopyA(volName, sizeof(volName), cp);
835 cp += strlen(volName)+1;
836 StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
837 cp += strlen(offLineMsg)+1;
838 StringCbCopyA(motd, sizeof(motd), cp);
840 if (volStat.MinQuota != -1) {
841 storeStat.MinQuota = volStat.MinQuota;
842 storeStat.Mask |= AFS_SETMINQUOTA;
844 if (volStat.MaxQuota != -1) {
845 storeStat.MaxQuota = volStat.MaxQuota;
846 storeStat.Mask |= AFS_SETMAXQUOTA;
850 code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
853 callp = cm_GetRxConn(tcp);
854 code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
855 &storeStat, volName, offLineMsg, motd);
856 rx_PutConnection(callp);
858 } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
859 code = cm_MapRPCError(code, &req);
862 /* return on failure */
863 cm_ReleaseSCache(scp);
868 /* we are sending parms back to make compat. with prev system. should
869 * change interface later to not ask for current status, just set
872 cp = ioctlp->outDatap;
873 memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
874 cp += sizeof(VolumeStatus);
875 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
876 cp += strlen(volName)+1;
877 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
878 cp += strlen(offLineMsg)+1;
879 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
880 cp += strlen(motd)+1;
882 /* now return updated return data pointer */
883 ioctlp->outDatap = cp;
888 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
892 char offLineMsg[256];
896 AFSFetchVolumeStatus volStat;
902 struct rx_connection * callp;
906 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
907 if (code) return code;
909 #ifdef AFS_FREELANCE_CLIENT
910 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
912 strncpy(volName, "Freelance.Local.Root", sizeof(volName));
913 offLineMsg[0] = '\0';
914 strncpy(motd, "Freelance mode in use.", sizeof(motd));
915 volStat.Vid = scp->fid.volume;
916 volStat.MaxQuota = 0;
917 volStat.BlocksInUse = 100;
918 volStat.PartBlocksAvail = 0;
919 volStat.PartMaxBlocks = 100;
924 OfflineMsg = offLineMsg;
927 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
930 callp = cm_GetRxConn(connp);
931 code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
932 &volStat, &Name, &OfflineMsg, &MOTD);
933 rx_PutConnection(callp);
935 } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
936 code = cm_MapRPCError(code, &req);
939 cm_ReleaseSCache(scp);
940 if (code) return code;
942 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
943 cp = ioctlp->outDatap;
944 memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
945 cp += sizeof(AFSFetchVolumeStatus);
946 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
947 cp += strlen(volName)+1;
948 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
949 cp += strlen(offLineMsg)+1;
950 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
951 cp += strlen(motd)+1;
953 /* return new size */
954 ioctlp->outDatap = cp;
959 long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
969 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
970 if (code) return code;
972 memset(&fid, 0, sizeof(cm_fid_t));
973 fid.volume = scp->fid.volume;
974 fid.vnode = scp->fid.vnode;
975 fid.unique = scp->fid.unique;
977 cm_ReleaseSCache(scp);
979 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
980 cp = ioctlp->outDatap;
981 memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
982 cp += sizeof(cm_fid_t);
984 /* return new size */
985 ioctlp->outDatap = cp;
990 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
999 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
1000 if (code) return code;
1002 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1003 cp = ioctlp->outDatap;
1004 memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
1005 cp += sizeof(afs_uint32);
1006 memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
1007 cp += sizeof(afs_uint32);
1009 /* return new size */
1010 ioctlp->outDatap = cp;
1012 cm_ReleaseSCache(scp);
1017 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1023 cm_serverRef_t **tsrpp, *current;
1025 unsigned long volume;
1031 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
1032 if (code) return code;
1034 volume = scp->fid.volume;
1036 cellp = cm_FindCellByID(scp->fid.cell);
1038 cm_ReleaseSCache(scp);
1041 return CM_ERROR_NOSUCHCELL;
1043 code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
1047 cp = ioctlp->outDatap;
1049 lock_ObtainMutex(&tvp->mx);
1050 tsrpp = cm_GetVolServers(tvp, volume);
1051 lock_ObtainRead(&cm_serverLock);
1052 for (current = *tsrpp; current; current = current->next) {
1053 tsp = current->server;
1054 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1057 lock_ReleaseRead(&cm_serverLock);
1058 cm_FreeServerList(tsrpp, 0);
1059 lock_ReleaseMutex(&tvp->mx);
1061 /* still room for terminating NULL, add it on */
1062 volume = 0; /* reuse vbl */
1063 memcpy(cp, (char *)&volume, sizeof(long));
1066 ioctlp->outDatap = cp;
1071 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1081 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1082 if (code) return code;
1084 cp = ioctlp->inDatap;
1086 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1087 cm_ReleaseSCache(dscp);
1088 if (code) return code;
1090 lock_ObtainMutex(&scp->mx);
1092 /* now check that this is a real mount point */
1093 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1094 lock_ReleaseMutex(&scp->mx);
1095 cm_ReleaseSCache(scp);
1096 return CM_ERROR_INVAL;
1099 code = cm_ReadMountPoint(scp, userp, &req);
1101 cp = ioctlp->outDatap;
1102 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1103 cp += strlen(cp) + 1;
1104 ioctlp->outDatap = cp;
1106 lock_ReleaseMutex(&scp->mx);
1107 cm_ReleaseSCache(scp);
1112 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1122 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1123 if (code) return code;
1125 cp = ioctlp->inDatap;
1127 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1129 /* if something went wrong, bail out now */
1134 lock_ObtainMutex(&scp->mx);
1135 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1136 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1138 lock_ReleaseMutex(&scp->mx);
1139 cm_ReleaseSCache(scp);
1143 /* now check that this is a real mount point */
1144 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1145 lock_ReleaseMutex(&scp->mx);
1146 cm_ReleaseSCache(scp);
1147 code = CM_ERROR_INVAL;
1151 /* time to make the RPC, so drop the lock */
1152 lock_ReleaseMutex(&scp->mx);
1153 cm_ReleaseSCache(scp);
1155 /* easier to do it this way */
1156 code = cm_Unlink(dscp, cp, userp, &req);
1157 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1158 smb_NotifyChange(FILE_ACTION_REMOVED,
1159 FILE_NOTIFY_CHANGE_DIR_NAME,
1160 dscp, cp, NULL, TRUE);
1163 lock_ObtainMutex(&scp->mx);
1164 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1165 lock_ReleaseMutex(&scp->mx);
1168 cm_ReleaseSCache(dscp);
1172 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1182 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1183 tp = ioctlp->inDatap;
1186 memcpy(&temp, tp, sizeof(temp));
1187 if (temp == 0x12345678) { /* For afs3.3 version */
1188 memcpy(&csi, tp, sizeof(csi));
1189 if (csi.tinterval >= 0) {
1190 cp = ioctlp->outDatap;
1191 memcpy(cp, (char *)&cm_daemonCheckDownInterval, sizeof(long));
1192 ioctlp->outDatap += sizeof(long);
1193 if (csi.tinterval > 0) {
1194 if (!smb_SUser(userp))
1195 return CM_ERROR_NOACCESS;
1196 cm_daemonCheckDownInterval = csi.tinterval;
1204 } else { /* For pre afs3.3 versions */
1205 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1206 ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
1207 if (cp - ioctlp->inAllocp < ioctlp->inCopied) /* still more data available */
1212 * 1: fast check, don't contact servers.
1213 * 2: local cell only.
1216 /* have cell name, too */
1217 cellp = cm_GetCell(cp, 0);
1219 return CM_ERROR_NOSUCHCELL;
1221 else cellp = (cm_cell_t *) 0;
1222 if (!cellp && (temp & 2)) {
1223 /* use local cell */
1224 cellp = cm_FindCellByID(1);
1226 if (!(temp & 1)) { /* if not fast, call server checker routine */
1227 /* check down servers */
1228 cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
1232 /* now return the current down server list */
1233 cp = ioctlp->outDatap;
1234 lock_ObtainRead(&cm_serverLock);
1235 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
1236 if (cellp && tsp->cellp != cellp) continue; /* cell spec'd and wrong */
1237 if ((tsp->flags & CM_SERVERFLAG_DOWN)
1238 && tsp->type == CM_SERVER_FILE) {
1239 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1243 lock_ReleaseRead(&cm_serverLock);
1245 ioctlp->outDatap = cp;
1249 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1251 /* we don't print anything superfluous, so we don't support the gag call */
1252 return CM_ERROR_INVAL;
1255 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1257 cm_RefreshVolumes();
1261 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1266 cm_SkipIoctlPath(ioctlp);
1268 memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1270 temp = cm_data.buf_nOrigBuffers;
1272 /* temp is in 1K units, convert to # of buffers */
1273 temp = temp / (cm_data.buf_blockSize / 1024);
1276 /* now adjust the cache size */
1277 code = buf_SetNBuffers(temp);
1282 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1286 cm_SkipIoctlPath(ioctlp);
1288 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1292 afsd_ForceTrace(FALSE);
1293 buf_ForceTrace(FALSE);
1297 /* set tracing value to low order bit */
1298 if ((inValue & 1) == 0) {
1299 /* disable tracing */
1300 osi_LogDisable(afsd_logp);
1301 rx_DebugOnOff(FALSE);
1304 /* enable tracing */
1305 osi_LogEnable(afsd_logp);
1306 rx_DebugOnOff(TRUE);
1310 /* see if we're supposed to do a reset, too */
1312 osi_LogReset(afsd_logp);
1315 /* and copy out tracing flag */
1316 inValue = afsd_logp->enabled; /* use as a temp vbl */
1317 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1318 ioctlp->outDatap += sizeof(long);
1322 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1324 cm_cacheParms_t parms;
1326 memset(&parms, 0, sizeof(parms));
1328 /* first we get, in 1K units, the cache size */
1329 parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1331 /* and then the actual # of buffers in use (not in the free list, I guess,
1332 * will be what we do).
1334 parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1336 memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1337 ioctlp->outDatap += sizeof(parms);
1342 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1347 cm_serverRef_t *serverRefp;
1348 cm_server_t *serverp;
1354 cm_SkipIoctlPath(ioctlp);
1356 tp = ioctlp->inDatap;
1358 memcpy((char *)&whichCell, tp, sizeof(long));
1361 /* see if more than one long passed in, ignoring the null pathname (the -1) */
1362 if (ioctlp->inCopied-1 > sizeof(long)) {
1363 memcpy((char *)&magic, tp, sizeof(long));
1366 lock_ObtainRead(&cm_cellLock);
1367 for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
1368 if (whichCell == 0) break;
1371 lock_ReleaseRead(&cm_cellLock);
1375 cp = ioctlp->outDatap;
1377 if (magic == 0x12345678) {
1378 memcpy(cp, (char *)&magic, sizeof(long));
1381 memset(cp, 0, max * sizeof(long));
1383 lock_ObtainRead(&cm_serverLock); /* for going down server list */
1384 /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1385 serverRefp = tcellp->vlServersp;
1386 for (i=0; i<max; i++) {
1387 if (!serverRefp) break;
1388 serverp = serverRefp->server;
1389 memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1391 serverRefp = serverRefp->next;
1393 lock_ReleaseRead(&cm_serverLock);
1394 cp = basep + max * sizeof(afs_int32);
1395 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
1396 cp += strlen(tcellp->name)+1;
1397 ioctlp->outDatap = cp;
1403 return CM_ERROR_NOMORETOKENS; /* mapped to EDOM */
1406 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1408 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1410 /* NT cache manager will read cell information from CellServDB each time
1411 * cell is accessed. So, this call is necessary only if list of server for a cell
1412 * changes (or IP addresses of cell servers changes).
1413 * All that needs to be done is to refresh server information for all cells that
1414 * are already loaded.
1416 * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1421 cm_SkipIoctlPath(ioctlp);
1422 lock_ObtainWrite(&cm_cellLock);
1424 for (cp = cm_data.allCellsp; cp; cp=cp->allNextp)
1427 lock_ObtainMutex(&cp->mx);
1428 /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1429 cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
1430 cp->vlServersp = NULL;
1431 code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1432 #ifdef AFS_AFSDB_ENV
1434 if (cm_dnsEnabled) {
1436 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1437 if ( code == 0 ) { /* got cell from DNS */
1438 cp->flags |= CM_CELLFLAG_DNS;
1439 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1440 cp->timeout = time(0) + ttl;
1445 cp->flags &= ~CM_CELLFLAG_DNS;
1447 #endif /* AFS_AFSDB_ENV */
1449 cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1452 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1453 cm_RandomizeServer(&cp->vlServersp);
1455 lock_ReleaseMutex(&cp->mx);
1458 lock_ReleaseWrite(&cm_cellLock);
1462 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1466 if (cm_freelanceEnabled) {
1467 if (cm_GetRootCellName(ioctlp->outDatap))
1468 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
1469 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1470 } else if (cm_data.rootCellp) {
1471 /* return the default cellname to the caller */
1472 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
1473 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1475 /* if we don't know our default cell, return failure */
1476 code = CM_ERROR_NOSUCHCELL;
1482 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1484 long setSysName, foundname = 0;
1485 char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1486 int t, count, num = 0;
1487 char **sysnamelist[MAXSYSNAME];
1489 cm_SkipIoctlPath(ioctlp);
1491 memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1492 ioctlp->inDatap += sizeof(long);
1496 if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1498 cp2 = ioctlp->inDatap;
1499 for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1500 /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1501 t = (int)strlen(cp);
1502 if (t >= MAXSYSNAME || t <= 0)
1504 /* check for names that can shoot us in the foot */
1505 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1511 /* inname gets first entry in case we're being a translator */
1512 /* (we are never a translator) */
1513 t = (int)strlen(ioctlp->inDatap);
1514 memcpy(inname, ioctlp->inDatap, t + 1);
1515 ioctlp->inDatap += t + 1;
1519 /* Not xlating, so local case */
1521 osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1523 if (!setSysName) { /* user just wants the info */
1524 StringCbCopyA(outname, sizeof(outname), cm_sysName);
1525 foundname = cm_sysNameCount;
1526 *sysnamelist = cm_sysNameList;
1528 /* Local guy; only root can change sysname */
1529 /* clear @sys entries from the dnlc, once afs_lookup can
1530 * do lookups of @sys entries and thinks it can trust them */
1531 /* privs ok, store the entry, ... */
1532 StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1533 StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1534 if (setSysName > 1) { /* ... or list */
1535 cp = ioctlp->inDatap;
1536 for (count = 1; count < setSysName; ++count) {
1537 if (!cm_sysNameList[count])
1538 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1539 __FILE__, __LINE__);
1540 t = (int)strlen(cp);
1541 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1545 cm_sysNameCount = setSysName;
1549 /* return the sysname to the caller */
1550 cp = ioctlp->outDatap;
1551 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1552 cp += sizeof(afs_int32); /* skip found flag */
1554 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
1555 cp += strlen(outname) + 1; /* skip name and terminating null char */
1556 for ( count=1; count < foundname ; ++count) { /* ... or list */
1557 if ( !(*sysnamelist)[count] )
1558 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n",
1559 __FILE__, __LINE__);
1560 t = (int)strlen((*sysnamelist)[count]);
1561 if (t >= MAXSYSNAME)
1562 osi_panic("cm_IoctlSysName: sysname entry garbled\n",
1563 __FILE__, __LINE__);
1564 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
1568 ioctlp->outDatap = cp;
1575 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1580 cm_SkipIoctlPath(ioctlp);
1582 cellp = cm_GetCell(ioctlp->inDatap, 0);
1584 return CM_ERROR_NOSUCHCELL;
1587 lock_ObtainMutex(&cellp->mx);
1588 if (cellp->flags & CM_CELLFLAG_SUID)
1589 temp |= CM_SETCELLFLAG_SUID;
1590 lock_ReleaseMutex(&cellp->mx);
1592 /* now copy out parm */
1593 memcpy(ioctlp->outDatap, &temp, sizeof(long));
1594 ioctlp->outDatap += sizeof(long);
1599 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1604 cm_SkipIoctlPath(ioctlp);
1606 cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1608 return CM_ERROR_NOSUCHCELL;
1610 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1612 lock_ObtainMutex(&cellp->mx);
1613 if (temp & CM_SETCELLFLAG_SUID)
1614 cellp->flags |= CM_CELLFLAG_SUID;
1616 cellp->flags &= ~CM_CELLFLAG_SUID;
1617 lock_ReleaseMutex(&cellp->mx);
1622 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1624 cm_SSetPref_t *spin; /* input */
1625 cm_SPref_t *srvin; /* one input component */
1627 int i, vlonly, noServers, type;
1628 struct sockaddr_in tmp;
1629 unsigned short rank;
1631 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1633 spin = (cm_SSetPref_t *)ioctlp->inDatap;
1634 noServers = spin->num_servers;
1635 vlonly = spin->flags;
1637 type = CM_SERVER_VLDB;
1639 type = CM_SERVER_FILE;
1641 for ( i=0; i < noServers; i++)
1643 srvin = &(spin->servers[i]);
1644 rank = srvin->rank + (rand() & 0x000f);
1645 tmp.sin_addr = srvin->host;
1646 tmp.sin_family = AF_INET;
1648 tsp = cm_FindServer(&tmp, type);
1649 if ( tsp ) /* an existing server - ref count increased */
1651 tsp->ipRank = rank; /* no need to protect by mutex*/
1653 if (type == CM_SERVER_FILE)
1655 /* find volumes which might have RO copy
1656 /* on server and change the ordering of
1659 cm_ChangeRankVolume(tsp);
1663 /* set preferences for an existing vlserver */
1664 cm_ChangeRankCellVLServer(tsp);
1667 else /* add a new server without a cell */
1669 tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
1672 lock_ObtainMutex(&tsp->mx);
1673 tsp->flags |= CM_SERVERFLAG_PREF_SET;
1674 lock_ReleaseMutex(&tsp->mx);
1675 cm_PutServer(tsp); /* decrease refcount */
1680 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1682 cm_SPrefRequest_t *spin; /* input */
1683 cm_SPrefInfo_t *spout; /* output */
1684 cm_SPref_t *srvout; /* one output component */
1686 int i, vlonly, noServers;
1688 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1690 spin = (cm_SPrefRequest_t *)ioctlp->inDatap;
1691 spout = (cm_SPrefInfo_t *) ioctlp->outDatap;
1692 srvout = spout->servers;
1693 noServers = spin->num_servers;
1694 vlonly = spin->flags & CM_SPREF_VLONLY;
1695 spout->num_servers = 0;
1697 lock_ObtainRead(&cm_serverLock); /* get server lock */
1699 for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1700 if (spin->offset > i) {
1701 continue; /* catch up to where we left off */
1704 if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1705 continue; /* ignore fileserver for -vlserver option*/
1706 if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1707 continue; /* ignore vlservers */
1709 srvout->host = tsp->addr.sin_addr;
1710 srvout->rank = tsp->ipRank;
1712 spout->num_servers++;
1715 lock_ReleaseRead(&cm_serverLock); /* release server lock */
1717 if ( tsp ) /* we ran out of space in the output buffer */
1718 spout->next_offset = i;
1720 spout->next_offset = 0;
1721 ioctlp->outDatap += sizeof(cm_SPrefInfo_t) +
1722 (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1726 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1728 /* we ignore default asynchrony since we only have one way
1729 * of doing this today.
1734 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1736 char leaf[LEAF_SIZE];
1750 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1754 /* Translate chars for the mount point name */
1755 TranslateExtendedChars(leaf);
1758 * The fs command allows the user to specify partial cell names on NT. These must
1759 * be expanded to the full cell name for mount points so that the mount points will
1760 * work on UNIX clients.
1763 /* Extract the possibly partial cell name */
1764 StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1); /* Skip the mp type character */
1766 if (cp = strchr(cell, ':')) {
1767 /* Extract the volume name */
1769 StringCbCopyA(volume, sizeof(volume), cp + 1);
1771 /* Get the full name for this cell */
1772 code = cm_SearchCellFile(cell, fullCell, 0, 0);
1773 #ifdef AFS_AFSDB_ENV
1774 if (code && cm_dnsEnabled)
1775 code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1778 cm_ReleaseSCache(dscp);
1779 return CM_ERROR_NOSUCHCELL;
1782 StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1784 /* No cell name specified */
1785 StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1788 #ifdef AFS_FREELANCE_CLIENT
1789 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1790 /* we are adding the mount point to the root dir., so call
1791 * the freelance code to do the add. */
1792 osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1793 code = cm_FreelanceAddMount(leaf, fullCell, volume,
1794 *ioctlp->inDatap == '%', NULL);
1795 cm_ReleaseSCache(dscp);
1799 /* create the symlink with mode 644. The lack of X bits tells
1800 * us that it is a mount point.
1802 tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1803 tattr.unixModeBits = 0644;
1804 tattr.clientModTime = time(NULL);
1806 code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1807 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1808 smb_NotifyChange(FILE_ACTION_ADDED,
1809 FILE_NOTIFY_CHANGE_DIR_NAME,
1810 dscp, leaf, NULL, TRUE);
1812 cm_ReleaseSCache(dscp);
1816 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1818 char leaf[LEAF_SIZE];
1827 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1828 if (code) return code;
1830 /* Translate chars for the link name */
1831 TranslateExtendedChars(leaf);
1833 /* Translate chars for the linked to name */
1834 TranslateExtendedChars(ioctlp->inDatap);
1836 cp = ioctlp->inDatap; /* contents of link */
1838 #ifdef AFS_FREELANCE_CLIENT
1839 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1840 /* we are adding the symlink to the root dir., so call
1841 * the freelance code to do the add. */
1842 if (cp[0] == cp[1] && cp[1] == '\\' &&
1843 !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName)))
1845 /* skip \\AFS\ or \\AFS\all\ */
1847 p = cp + 2 + strlen(cm_NetbiosName) + 1;
1848 if ( !_strnicmp("all", p, 3) )
1852 osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1853 code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1854 cm_ReleaseSCache(dscp);
1859 /* Create symlink with mode 0755. */
1860 tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1861 tattr.unixModeBits = 0755;
1863 code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1864 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1865 smb_NotifyChange(FILE_ACTION_ADDED,
1866 FILE_NOTIFY_CHANGE_FILE_NAME
1867 | FILE_NOTIFY_CHANGE_DIR_NAME,
1868 dscp, leaf, NULL, TRUE);
1870 cm_ReleaseSCache(dscp);
1876 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1883 cm_scache_t *newRootScp;
1888 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1889 if (code) return code;
1891 cp = ioctlp->inDatap;
1893 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1894 cm_ReleaseSCache(dscp);
1895 if (code) return code;
1897 /* Check that it's a real symlink */
1898 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1899 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1900 scp->fileType != CM_SCACHETYPE_INVALID) {
1901 cm_ReleaseSCache(scp);
1902 return CM_ERROR_INVAL;
1905 code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1906 cm_ReleaseSCache(scp);
1908 cp = ioctlp->outDatap;
1909 if (newRootScp != NULL) {
1910 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
1911 StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
1914 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
1915 cp += strlen(cp) + 1;
1916 ioctlp->outDatap = cp;
1917 cm_FreeSpace(spacep);
1918 if (newRootScp != NULL)
1919 cm_ReleaseSCache(newRootScp);
1921 } else if (code == CM_ERROR_PATH_NOT_COVERED &&
1922 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1923 code == CM_ERROR_NOSUCHPATH &&
1924 scp->fileType == CM_SCACHETYPE_INVALID) {
1925 cp = ioctlp->outDatap;
1926 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
1927 cp += strlen(cp) + 1;
1928 ioctlp->outDatap = cp;
1929 cm_FreeSpace(spacep);
1930 if (newRootScp != NULL)
1931 cm_ReleaseSCache(newRootScp);
1938 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1939 {/*CHECK FOR VALID SYMLINK*/
1948 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1949 if (code) return code;
1951 cp = ioctlp->inDatap;
1952 osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1954 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1955 cm_ReleaseSCache(dscp);
1956 if (code) return code;
1958 /* Check that it's a real symlink */
1959 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1960 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1961 scp->fileType != CM_SCACHETYPE_INVALID)
1962 code = CM_ERROR_INVAL;
1963 cm_ReleaseSCache(scp);
1967 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1977 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1978 if (code) return code;
1980 cp = ioctlp->inDatap;
1982 #ifdef AFS_FREELANCE_CLIENT
1983 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1984 /* we are adding the mount point to the root dir., so call
1985 * the freelance code to do the add. */
1986 osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
1987 code = cm_FreelanceRemoveSymlink(cp);
1988 cm_ReleaseSCache(dscp);
1993 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1995 /* if something went wrong, bail out now */
1999 lock_ObtainMutex(&scp->mx);
2000 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2001 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2005 /* now check that this is a real symlink */
2006 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
2007 scp->fileType != CM_SCACHETYPE_DFSLINK &&
2008 scp->fileType != CM_SCACHETYPE_INVALID) {
2009 code = CM_ERROR_INVAL;
2013 /* time to make the RPC, so drop the lock */
2014 lock_ReleaseMutex(&scp->mx);
2016 /* easier to do it this way */
2017 code = cm_Unlink(dscp, cp, userp, &req);
2018 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2019 smb_NotifyChange(FILE_ACTION_REMOVED,
2020 FILE_NOTIFY_CHANGE_FILE_NAME
2021 | FILE_NOTIFY_CHANGE_DIR_NAME,
2022 dscp, cp, NULL, TRUE);
2024 lock_ObtainMutex(&scp->mx);
2026 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2029 lock_ReleaseMutex(&scp->mx);
2030 cm_ReleaseSCache(scp);
2033 cm_ReleaseSCache(dscp);
2038 long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
2043 static struct afsconf_cell info;
2044 struct rx_connection *serverconns[MAXSERVERS];
2045 struct rx_securityClass *sc[3];
2046 afs_int32 scIndex = 2; /* authenticated - we have a token */
2047 struct ubik_client *pruclient = NULL;
2048 struct afsconf_dir *tdir;
2052 tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
2053 code = afsconf_GetCellInfo(tdir, ucellp->cellp->name, "afsprot", &info);
2054 afsconf_Close(tdir);
2060 /* we have the token that was given to us in the settoken
2061 * call. we just have to use it.
2063 scIndex = 2; /* kerberos ticket */
2064 sc[2] = rxkad_NewClientSecurityObject(rxkad_clear, &ucellp->sessionKey,
2065 ucellp->kvno, ucellp->ticketLen,
2068 memset(serverconns, 0, sizeof(serverconns)); /* terminate list!!! */
2069 for (i = 0; i < info.numServers; i++)
2071 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
2072 info.hostAddr[i].sin_port, PRSRV, sc[scIndex],
2075 code = ubik_ClientInit(serverconns, &pruclient);
2080 code = rxs_Release(sc[scIndex]);
2082 lids.idlist_len = 0;
2083 lids.idlist_val = 0;
2084 lnames.namelist_len = 1;
2085 lnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
2086 strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
2087 lnames.namelist_val[0][PR_MAXNAMELEN-1] = '\0';
2088 for ( p=lnames.namelist_val[0], r=NULL; *p; p++ ) {
2094 if (r && !stricmp(r+1,ucellp->cellp->name))
2097 code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
2098 if (lids.idlist_val) {
2099 *uid = *lids.idlist_val;
2100 free(lids.idlist_val);
2102 if (lnames.namelist_val)
2103 free(lnames.namelist_val);
2106 ubik_ClientDestroy(pruclient);
2112 #endif /* QUERY_AFSID */
2114 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2121 struct ClearToken ct;
2131 int release_userp = 0;
2134 saveDataPtr = ioctlp->inDatap;
2136 cm_SkipIoctlPath(ioctlp);
2138 tp = ioctlp->inDatap;
2141 memcpy(&ticketLen, tp, sizeof(ticketLen));
2142 tp += sizeof(ticketLen);
2143 if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
2144 return CM_ERROR_INVAL;
2146 /* remember ticket and skip over it for now */
2150 /* clear token size */
2151 memcpy(&ctSize, tp, sizeof(ctSize));
2152 tp += sizeof(ctSize);
2153 if (ctSize != sizeof(struct ClearToken))
2154 return CM_ERROR_INVAL;
2157 memcpy(&ct, tp, ctSize);
2159 if (ct.AuthHandle == -1)
2160 ct.AuthHandle = 999; /* more rxvab compat stuff */
2162 /* more stuff, if any */
2163 if (ioctlp->inCopied > tp - saveDataPtr) {
2164 /* flags: logon flag */
2165 memcpy(&flags, tp, sizeof(int));
2169 cellp = cm_GetCell(tp, CM_FLAG_CREATE);
2171 return CM_ERROR_NOSUCHCELL;
2172 tp += strlen(tp) + 1;
2176 tp += strlen(tp) + 1;
2178 #ifndef AFSIFS /* no SMB username, so we cannot logon based on this */
2179 if (flags & PIOCTL_LOGON) {
2180 /* SMB user name with which to associate tokens */
2182 osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
2183 osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
2184 fprintf(stderr, "SMB name = %s\n", smbname);
2185 tp += strlen(tp) + 1;
2187 osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
2188 osi_LogSaveString(smb_logp, uname));
2192 #ifndef DJGPP /* for win95, session key is back in pioctl */
2194 memcpy(&uuid, tp, sizeof(uuid));
2195 if (!cm_FindTokenEvent(uuid, sessionKey))
2196 return CM_ERROR_INVAL;
2199 cellp = cm_data.rootCellp;
2200 osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
2204 if (flags & PIOCTL_LOGON) {
2205 userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
2206 SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
2211 /* store the token */
2212 lock_ObtainMutex(&userp->mx);
2213 ucellp = cm_GetUCell(userp, cellp);
2214 osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
2215 ucellp->ticketLen = ticketLen;
2216 if (ucellp->ticketp)
2217 free(ucellp->ticketp); /* Discard old token if any */
2218 ucellp->ticketp = malloc(ticketLen);
2219 memcpy(ucellp->ticketp, ticket, ticketLen);
2222 * Get the session key from the RPC, rather than from the pioctl.
2225 memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2227 memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
2229 /* for win95, we are getting the session key from the pioctl */
2230 memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2232 ucellp->kvno = ct.AuthHandle;
2233 ucellp->expirationTime = ct.EndTimestamp;
2236 ucellp->uid = ANONYMOUSID;
2239 StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
2241 cm_UsernameToId(uname, ucellp, &ucellp->uid);
2244 ucellp->flags |= CM_UCELLFLAG_RXKAD;
2245 lock_ReleaseMutex(&userp->mx);
2247 if (flags & PIOCTL_LOGON) {
2248 ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
2251 cm_ResetACLCache(userp);
2254 cm_ReleaseUser(userp);
2259 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
2265 struct ClearToken ct;
2267 cm_SkipIoctlPath(ioctlp);
2269 tp = ioctlp->inDatap;
2270 cp = ioctlp->outDatap;
2273 memcpy(&iterator, tp, sizeof(iterator));
2274 tp += sizeof(iterator);
2276 lock_ObtainMutex(&userp->mx);
2278 /* look for token */
2279 for (;;iterator++) {
2280 ucellp = cm_FindUCell(userp, iterator);
2282 lock_ReleaseMutex(&userp->mx);
2283 return CM_ERROR_NOMORETOKENS;
2285 if (ucellp->flags & CM_UCELLFLAG_RXKAD)
2290 temp = ucellp->iterator + 1;
2291 memcpy(cp, &temp, sizeof(temp));
2295 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2296 cp += sizeof(ucellp->ticketLen);
2299 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2300 cp += ucellp->ticketLen;
2302 /* clear token size */
2304 memcpy(cp, &temp, sizeof(temp));
2308 ct.AuthHandle = ucellp->kvno;
2311 * Don't give out a real session key here
2314 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2316 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2318 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2320 ct.ViceId = 37; /* XXX */
2321 ct.BeginTimestamp = 0; /* XXX */
2322 ct.EndTimestamp = ucellp->expirationTime;
2323 memcpy(cp, &ct, sizeof(ct));
2326 /* Primary flag (unused) */
2328 memcpy(cp, &temp, sizeof(temp));
2332 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2333 cp += strlen(cp) + 1;
2336 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2337 cp += strlen(cp) + 1;
2339 ioctlp->outDatap = cp;
2341 lock_ReleaseMutex(&userp->mx);
2346 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2352 struct ClearToken ct;
2358 cm_SkipIoctlPath(ioctlp);
2360 tp = ioctlp->inDatap;
2362 cp = ioctlp->outDatap;
2364 /* cell name is right here */
2365 cellp = cm_GetCell(tp, 0);
2367 return CM_ERROR_NOSUCHCELL;
2368 tp += strlen(tp) + 1;
2372 memcpy(&uuid, tp, sizeof(uuid));
2375 lock_ObtainMutex(&userp->mx);
2377 ucellp = cm_GetUCell(userp, cellp);
2378 if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2379 lock_ReleaseMutex(&userp->mx);
2380 return CM_ERROR_NOMORETOKENS;
2384 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2385 cp += sizeof(ucellp->ticketLen);
2388 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2389 cp += ucellp->ticketLen;
2391 /* clear token size */
2393 memcpy(cp, &temp, sizeof(temp));
2397 ct.AuthHandle = ucellp->kvno;
2400 * Don't give out a real session key here
2403 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2405 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2407 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2409 ct.ViceId = 37; /* XXX */
2410 ct.BeginTimestamp = 0; /* XXX */
2411 ct.EndTimestamp = ucellp->expirationTime;
2412 memcpy(cp, &ct, sizeof(ct));
2415 /* Primary flag (unused) */
2417 memcpy(cp, &temp, sizeof(temp));
2421 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->cellp->name);
2422 cp += strlen(cp) + 1;
2425 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), ucellp->userName);
2426 cp += strlen(cp) + 1;
2428 ioctlp->outDatap = cp;
2430 lock_ReleaseMutex(&userp->mx);
2433 cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2439 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2445 cm_SkipIoctlPath(ioctlp);
2447 cp = ioctlp->outDatap;
2449 /* cell name is right here */
2450 cellp = cm_GetCell(ioctlp->inDatap, 0);
2452 return CM_ERROR_NOSUCHCELL;
2454 lock_ObtainMutex(&userp->mx);
2456 ucellp = cm_GetUCell(userp, cellp);
2458 lock_ReleaseMutex(&userp->mx);
2459 return CM_ERROR_NOMORETOKENS;
2462 osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2464 if (ucellp->ticketp) {
2465 free(ucellp->ticketp);
2466 ucellp->ticketp = NULL;
2468 ucellp->ticketLen = 0;
2469 memset(ucellp->sessionKey.data, 0, 8);
2471 ucellp->expirationTime = 0;
2472 ucellp->userName[0] = '\0';
2473 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2476 lock_ReleaseMutex(&userp->mx);
2478 cm_ResetACLCache(userp);
2483 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2487 lock_ObtainMutex(&userp->mx);
2489 for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2490 osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2492 if (ucellp->ticketp) {
2493 free(ucellp->ticketp);
2494 ucellp->ticketp = NULL;
2496 ucellp->ticketLen = 0;
2497 memset(ucellp->sessionKey.data, 0, 8);
2499 ucellp->expirationTime = 0;
2500 ucellp->userName[0] = '\0';
2501 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2505 lock_ReleaseMutex(&userp->mx);
2507 cm_ResetACLCache(userp);
2512 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2514 char afspath[MAX_PATH];
2516 int nextAutoSubmount;
2518 DWORD dwType, dwSize;
2523 cm_SkipIoctlPath(ioctlp);
2525 /* Serialize this one, to prevent simultaneous mods
2528 lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2530 /* Parse the input parameters--first the required afs path,
2531 * then the requested submount name (which may be "").
2533 cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2534 submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2536 /* If the caller supplied a suggested submount name, see if
2537 * that submount name is in use... if so, the submount's path
2538 * has to match our path.
2541 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2542 AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2545 REG_OPTION_NON_VOLATILE,
2546 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2551 if (submountreqp && *submountreqp) {
2552 char submountPathNormalized[MAX_PATH];
2553 char submountPath[MAX_PATH];
2555 dwSize = sizeof(submountPath);
2556 status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2557 &dwType, submountPath, &dwSize);
2559 if (status != ERROR_SUCCESS) {
2561 /* The suggested submount name isn't in use now--
2562 * so we can safely map the requested submount name
2563 * to the supplied path. Remember not to write the
2564 * leading "/afs" when writing out the submount.
2566 RegSetValueEx( hkSubmounts, submountreqp, 0,
2568 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2569 &afspath[strlen(cm_mountRoot)]:"/",
2570 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2571 (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2573 RegCloseKey( hkSubmounts );
2574 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2575 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2576 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2580 /* The suggested submount name is already in use--if the
2581 * supplied path matches the submount's path, we can still
2582 * use the suggested submount name.
2584 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2585 if (!strcmp (submountPathNormalized, afspath)) {
2586 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
2587 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2588 RegCloseKey( hkSubmounts );
2589 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2594 RegQueryInfoKey( hkSubmounts,
2596 NULL, /* lpcClass */
2597 NULL, /* lpReserved */
2598 NULL, /* lpcSubKeys */
2599 NULL, /* lpcMaxSubKeyLen */
2600 NULL, /* lpcMaxClassLen */
2601 &dwSubmounts, /* lpcValues */
2602 NULL, /* lpcMaxValueNameLen */
2603 NULL, /* lpcMaxValueLen */
2604 NULL, /* lpcbSecurityDescriptor */
2605 NULL /* lpftLastWriteTime */
2609 /* Having obtained a list of all available submounts, start
2610 * searching that list for a path which matches the requested
2611 * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2612 * submount, in case we need to add a new one later.
2615 nextAutoSubmount = 1;
2617 for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2618 char submountPathNormalized[MAX_PATH];
2619 char submountPath[MAX_PATH] = "";
2620 DWORD submountPathLen = sizeof(submountPath);
2621 char submountName[MAX_PATH];
2622 DWORD submountNameLen = sizeof(submountName);
2625 RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2626 &dwType, submountPath, &submountPathLen);
2627 if (dwType == REG_EXPAND_SZ) {
2629 StringCbCopyA(buf, MAX_PATH, submountPath);
2630 submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2631 if (submountPathLen > MAX_PATH)
2635 /* If this is an Auto### submount, remember its ### value */
2636 if ((!strnicmp (submountName, "auto", 4)) &&
2637 (isdigit (submountName[strlen("auto")]))) {
2638 int thisAutoSubmount;
2639 thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2640 nextAutoSubmount = max (nextAutoSubmount,
2641 thisAutoSubmount+1);
2644 if ((submountPathLen == 0) ||
2645 (submountPathLen == sizeof(submountPath) - 1)) {
2649 /* See if the path for this submount matches the path
2650 * that our caller specified. If so, we can return
2653 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2654 if (!strcmp (submountPathNormalized, afspath)) {
2655 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
2656 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2657 RegCloseKey(hkSubmounts);
2658 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2664 /* We've been through the entire list of existing submounts, and
2665 * didn't find any which matched the specified path. So, we'll
2666 * just have to add one. Remember not to write the leading "/afs"
2667 * when writing out the submount.
2670 StringCbPrintfA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "auto%ld", nextAutoSubmount);
2672 RegSetValueEx( hkSubmounts,
2676 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2677 &afspath[strlen(cm_mountRoot)]:"/",
2678 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2679 (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2681 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2682 RegCloseKey(hkSubmounts);
2683 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2687 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2689 memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2690 ioctlp->outDatap += sizeof(cryptall);
2695 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2697 afs_int32 c = cryptall;
2699 cm_SkipIoctlPath(ioctlp);
2701 memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2703 if (c != cryptall) {
2705 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
2707 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
2712 long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
2717 cm_SkipIoctlPath(ioctlp);
2719 memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2720 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2723 if (flags & AFSCALL_RXSTATS_ENABLE) {
2724 rx_enableProcessRPCStats();
2726 if (flags & AFSCALL_RXSTATS_DISABLE) {
2727 rx_disableProcessRPCStats();
2729 if (flags & AFSCALL_RXSTATS_CLEAR) {
2730 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
2735 long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
2740 cm_SkipIoctlPath(ioctlp);
2742 memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2743 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2746 if (flags & AFSCALL_RXSTATS_ENABLE) {
2747 rx_enablePeerRPCStats();
2749 if (flags & AFSCALL_RXSTATS_DISABLE) {
2750 rx_disablePeerRPCStats();
2752 if (flags & AFSCALL_RXSTATS_CLEAR) {
2753 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
2759 extern int afsd_shutdown(int);
2760 extern int afs_shutdown;
2762 long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
2763 afs_shutdown = 1; /* flag to shut down */
2768 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
2770 smb_user_t *uidp = ioctlp->uidp;
2772 if (uidp && uidp->unp) {
2773 memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
2774 ioctlp->outDatap += strlen(uidp->unp->name);
2780 long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
2785 memcpy(&cmd, ioctlp->inDatap, sizeof(long));
2787 if (cmd) { /* generate a new UUID */
2788 UuidCreate((UUID *) &uuid);
2789 cm_data.Uuid = uuid;
2790 cm_ForceNewConnectionsAllServers();
2793 memcpy(ioctlp->outDatap, &cm_data.Uuid, sizeof(cm_data.Uuid));
2794 ioctlp->outDatap += sizeof(cm_data.Uuid);
2800 * functions to dump contents of various structures.
2801 * In debug build (linked with crt debug library) will dump allocated but not freed memory
2803 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
2804 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
2805 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
2807 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
2811 char logfileName[MAX_PATH+1];
2816 static _CrtMemState memstate;
2819 cm_SkipIoctlPath(ioctlp);
2820 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
2822 dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
2823 if ( dwSize == 0 || dwSize > sizeof(logfileName) )
2825 GetWindowsDirectory(logfileName, sizeof(logfileName));
2827 strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
2829 hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2835 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2836 ioctlp->outDatap += sizeof(long);
2841 SetFilePointer(hLogFile, 0, NULL, FILE_END);
2843 cookie = inValue ? "b" : "e";
2849 _CrtMemCheckpoint(&memstate);
2853 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2854 _CrtSetReportFile(_CRT_WARN, hLogFile);
2855 _CrtMemDumpAllObjectsSince(&memstate);
2859 /* dump all interesting data */
2860 cm_MemDumpDirStats(hLogFile, cookie, 1);
2861 cm_MemDumpBPlusStats(hLogFile, cookie, 1);
2862 cm_DumpCells(hLogFile, cookie, 1);
2863 cm_DumpVolumes(hLogFile, cookie, 1);
2864 cm_DumpSCache(hLogFile, cookie, 1);
2865 cm_DumpBufHashTable(hLogFile, cookie, 1);
2866 smb_DumpVCP(hLogFile, cookie, 1);
2868 CloseHandle(hLogFile);
2870 inValue = 0; /* success */
2871 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2872 ioctlp->outDatap += sizeof(long);
2879 cm_CheckServersStatus(cm_serverRef_t *serversp)
2882 cm_serverRef_t *tsrp;
2884 int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
2886 if (serversp == NULL) {
2887 osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", CM_ERROR_ALLDOWN);
2888 return CM_ERROR_ALLDOWN;
2891 lock_ObtainRead(&cm_serverLock);
2892 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
2893 if (tsp = tsrp->server) {
2894 cm_GetServerNoLock(tsp);
2895 lock_ReleaseRead(&cm_serverLock);
2896 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
2898 if (tsrp->status == srv_busy) {
2901 } else if (tsrp->status == srv_offline) {
2911 lock_ObtainRead(&cm_serverLock);
2912 cm_PutServerNoLock(tsp);
2915 lock_ReleaseRead(&cm_serverLock);
2918 code = CM_ERROR_ALLDOWN;
2920 code = CM_ERROR_ALLBUSY;
2921 else if (allOffline || (someBusy && someOffline))
2922 code = CM_ERROR_ALLOFFLINE;
2925 osi_Log1(afsd_logp, "cm_CheckServersStatus returning 0x%x", code);
2930 long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
2936 cm_vol_state_t *statep;
2942 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
2946 #ifdef AFS_FREELANCE_CLIENT
2947 if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
2949 cm_ReleaseSCache(scp);
2953 volume = scp->fid.volume;
2955 cellp = cm_FindCellByID(scp->fid.cell);
2957 cm_ReleaseSCache(scp);
2960 return CM_ERROR_NOSUCHCELL;
2962 code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
2966 if (volume == tvp->rw.ID)
2968 else if (volume == tvp->ro.ID)
2973 switch (statep->state) {
2979 code = CM_ERROR_ALLBUSY;
2982 code = CM_ERROR_ALLOFFLINE;
2985 code = CM_ERROR_ALLDOWN;