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 <afsconfig.h>
11 #include <afs/param.h>
28 #include <WINNT/afsreg.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include <sys/param.h>
36 #endif /* AFS_NT40_ENV */
41 #include <afs/afs_Admin.h>
42 #include <afs/afs_AdminErrors.h>
43 #include <afs/afs_bosAdmin.h>
44 #include <afs/afs_clientAdmin.h>
46 #include <afs/dirpath.h>
48 #include "cfginternal.h"
49 #include "../adminutil/afs_AdminInternal.h"
53 * cfgutil_HostHandleValidate() -- validate a host configuration handle
55 * RETURN CODES: 1 success, 0 failure
58 cfgutil_HostHandleValidate(const cfg_host_p cfg_host, afs_status_p st)
63 if (cfg_host == NULL) {
64 tst = ADMCFGHOSTHANDLENULL;
66 } else if (cfg_host->begin_magic != BEGIN_MAGIC
67 || cfg_host->end_magic != END_MAGIC) {
68 tst = ADMCFGHOSTHANDLEBADMAGIC;
70 } else if (cfg_host->is_valid == 0) {
71 tst = ADMCFGHOSTHANDLEINVALID;
73 } else if (cfg_host->hostName == NULL) {
74 tst = ADMCFGHOSTHANDLEHOSTNAMENULL;
76 } else if (cfg_host->cellHandle == NULL) {
77 tst = ADMCFGHOSTHANDLECELLHANDLENULL;
79 } else if (cfg_host->cellName == NULL) {
80 tst = ADMCFGHOSTHANDLECELLNAMENULL;
84 /* indicate failure */
95 * cfgutil_HostHandleBosInit() -- initialize bosserver handle in host
96 * configuration handle.
98 * RETURN CODES: 1 success, 0 failure
101 cfgutil_HostHandleBosInit(cfg_host_p cfg_host, afs_status_p st)
104 afs_status_t tst = 0;
106 if (pthread_mutex_lock(&cfg_host->mutex)) {
109 if (cfg_host->bosHandle == NULL) {
110 /* initialize bosserver handle for host */
115 (cfg_host->cellHandle, cfg_host->hostName, &bosHandle,
117 cfg_host->bosHandle = bosHandle;
122 if (pthread_mutex_unlock(&cfg_host->mutex)) {
123 /* can only return one status; mutex failure is critical */
124 tst = ADMMUTEXUNLOCK;
129 /* indicate failure */
140 * cfgutil_HostHandleCellNameCompatible() -- determine if specified cell name
141 * is compatible with the cell name in the given cfg handle.
143 * RETURN CODES: 1 compatible, 0 not compatible
146 cfgutil_HostHandleCellNameCompatible(const cfg_host_p cfg_host,
147 const char *cellName)
151 if (*cfg_host->cellName == '\0') {
152 /* null cell handle; any cell name compatible by definition */
155 /* standard cell handle; compare cell names */
156 rc = (strcasecmp(cfg_host->cellName, cellName) == 0 ? 1 : 0);
163 * cfgutil_HostNameGetFull() -- return fully qualified version of specified
166 * Note: fullHostName is presumed to be a buffer of size MAXHOSTCHARS.
168 * RETURN CODES: 1 success, 0 failure
171 cfgutil_HostNameGetFull(const char *hostName, char *fullHostName,
175 afs_status_t tst = 0;
178 /* Note: gethostbyname() allocs hostent on a per-thread basis */
179 struct hostent *hentryp;
181 if ((hentryp = gethostbyname(hostName)) == NULL) {
182 tst = ADMCFGCANTRESOLVEHOSTNAME;
184 size_t hostNameLen = strlen(hostName);
185 char *fqName = hentryp->h_name;
187 /* verify that canonical name is an expansion of name specified */
188 if (strncasecmp(fqName, hostName, hostNameLen) != 0
189 || fqName[hostNameLen] != '.') {
190 /* canonical name not a direct expansion; consider aliases */
193 for (i = 0; hentryp->h_aliases[i] != NULL; i++) {
194 char *aliasName = hentryp->h_aliases[i];
195 if (strncasecmp(aliasName, hostName, hostNameLen) == 0
196 && aliasName[hostNameLen] == '.') {
197 /* found a direct exapansion of specified name */
204 if (strlen(fqName) > (MAXHOSTCHARS - 1)) {
205 tst = ADMCFGRESOLVEDHOSTNAMETOOLONG;
207 strcpy(fullHostName, fqName);
209 /* lower-case name for consistency */
210 _strlwr(fullHostName);
214 /* function not yet implemented for Unix */
215 tst = ADMCFGNOTSUPPORTED;
216 #endif /* AFS_NT40_ENV */
219 /* indicate failure */
230 * cfgutil_HostNameIsAlias() -- determine if specified host names
231 * are aliases (functionally equivalent).
233 * RETURN CODES: 1 success, 0 failure
236 cfgutil_HostNameIsAlias(const char *hostName1, const char *hostName2,
237 short *isAlias, afs_status_p st)
240 afs_status_t tst2, tst = 0;
241 int addrCount1, addrCount2;
242 afs_int32 *addrList1 = NULL, *addrList2 = NULL;
244 /* get all addrs for first host */
246 if (!cfgutil_HostAddressFetchAll
247 (hostName1, &addrCount1, &addrList1, &tst2)) {
251 /* get all addrs for second host */
254 if (!cfgutil_HostAddressFetchAll
255 (hostName2, &addrCount2, &addrList2, &tst2)) {
264 /* compare lists looking for a match */
271 for (i = 0; i < addrCount1; i++) {
272 for (j = 0; j < addrCount2; j++) {
273 if (addrList1[i] == addrList2[j]) {
290 /* indicate failure */
301 * cfgutil_HostNameIsLocal() -- determine if the specified host name is
302 * equivalent to (is an alias for) the standard host name for the
303 * machine on which this process is running.
305 * RETURN CODES: 1 success, 0 failure
308 cfgutil_HostNameIsLocal(const char *hostName, short *isLocal, afs_status_p st)
311 afs_status_t tst2, tst = 0;
312 char localName[MAXHOSTCHARS];
314 if (gethostname(localName, MAXHOSTCHARS)) {
315 /* failed to lookup local name */
316 tst = ADMCANTGETLOCALNAME;
317 } else if (!cfgutil_HostNameIsAlias(hostName, localName, isLocal, &tst2)) {
322 /* indicate failure */
333 * cfgutil_HostNameGetCellServDbAlias() -- Get alias for given host name
334 * as listed in the server CellServDB on the specified host. If no
335 * alias is found then hostNameAlias is set to the empty string.
337 * Note: hostNameAlias is presumed to be a buffer of size MAXHOSTCHARS.
339 * RETURN CODES: 1 success, 0 failure
342 cfgutil_HostNameGetCellServDbAlias(const char *fsDbHost, const char *hostName,
343 char *hostNameAlias, afs_status_p st)
346 afs_status_t tst2, tst = 0;
350 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
353 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
358 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
361 short dbhostDone = 0;
362 short dbhostFound = 0;
364 while (!dbhostDone) {
367 if (!bos_HostGetNext(dbIter, hostNameAlias, &tst2)) {
368 /* no more entries (or failure) */
369 if (tst2 != ADMITERATORDONE) {
375 if (!cfgutil_HostNameIsAlias
376 (hostName, hostNameAlias, &isAlias, &tst2)) {
380 } else if (isAlias) {
387 *hostNameAlias = '\0';
390 if (!bos_HostGetDone(dbIter, &tst2)) {
395 if (!bos_ServerClose(bosHandle, &tst2)) {
400 if (!afsclient_CellClose(cellHandle, &tst2)) {
406 /* indicate failure */
417 * cfgutil_HostNameGetAddressString() -- Get IP address for specified host in
418 * in the canonical string form.
420 * Returns pointer to a per-thread buffer; do not deallocate.
423 cfgutil_HostNameGetAddressString(const char *hostName, const char **hostAddr,
427 afs_status_t tst2, tst = 0;
429 afs_int32 *addrList = NULL;
431 /* get address list for host */
433 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
437 /* convert first (canonical) address to string */
443 ina.s_addr = htonl(addrList[0]);
444 if ((inaString = inet_ntoa(ina)) == NULL) {
445 /* should never happen */
446 tst = ADMCFGCANTRESOLVEHOSTNAME;
448 *hostAddr = inaString;
457 /* indicate failure */
468 * cfgutil_HostAddressFetchAll() -- get allocated list of all known
469 * addresses for specified host.
471 * Note: upon success, *addrList is an address array in host byte order.
473 * RETURN CODES: 1 success, 0 failure
476 cfgutil_HostAddressFetchAll(const char *hostName, int *addrCount,
477 afs_int32 ** addrList, afs_status_p st)
480 afs_status_t tst = 0;
482 afs_int32 *aList = NULL;
485 /* Note: gethostbyname() allocs hostent on a per-thread basis */
486 struct hostent *hentryp;
488 if ((hentryp = gethostbyname(hostName)) == NULL) {
489 tst = ADMCFGCANTRESOLVEHOSTNAME;
493 /* assuming IPv4 addrs returned */
494 for (i = 0; hentryp->h_addr_list[i] != NULL; i++);
498 (afs_int32 *) malloc(aCount * sizeof(afs_int32))) == NULL) {
501 for (i = 0; i < aCount; i++) {
503 memcpy((void *)&hostAddr, (void *)hentryp->h_addr_list[i],
505 aList[i] = ntohl(hostAddr);
510 /* function not yet implemented for Unix */
511 tst = ADMCFGNOTSUPPORTED;
512 #endif /* AFS_NT40_ENV */
519 /* indicate failure */
530 * cfgutil_HostAddressIsValid() -- determine if address is a valid address
531 * for the named host.
533 * Note: hostAddr must be specified in host byte order
535 * RETURN CODES: 1 success, 0 failure
538 cfgutil_HostAddressIsValid(const char *hostName, int hostAddr, short *isValid,
542 afs_status_t tst2, tst = 0;
544 afs_int32 *addrList = NULL;
548 /* get all addrs for host */
550 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
554 /* search list looking for match */
559 for (i = 0; i < addrCount; i++) {
560 if (addrList[i] == hostAddr) {
572 /* indicate failure */
583 * cfgutil_CleanDirectory() -- remove all files from specified directory;
584 * function is NOT recursive.
586 * RETURN CODES: 1 success, 0 failure
589 cfgutil_CleanDirectory(const char *dirName, afs_status_p st)
592 afs_status_t tst = 0;
595 struct dirent *entryp;
596 char dirfile[MAXPATHLEN];
598 if ((dirp = opendir(dirName)) == NULL) {
599 /* cannot open directory */
600 if (errno == EACCES) {
603 /* otherwise assume directory does not exist, which is OK */
605 while ((entryp = readdir(dirp)) != NULL) {
606 /* remove file (except "." and "..") */
607 if (strcmp(entryp->d_name, ".") && strcmp(entryp->d_name, "..")) {
608 sprintf(dirfile, "%s/%s", dirName, entryp->d_name);
609 if (unlink(dirfile)) {
611 if (errno == EACCES) {
615 /* otherwise assume file removed by someone else or
616 * that file is a directory, which is OK.
622 (void)closedir(dirp);
626 /* indicate failure */
637 * cfgutil_HostSetNoAuthFlag() -- set AFS server authentication flag on host
639 * RETURN CODES: 1 success, 0 failure (st indicates why)
642 cfgutil_HostSetNoAuthFlag(const cfg_host_p cfg_host, short noAuth,
646 afs_status_t tst = 0;
648 /* remote configuration not yet supported in this function */
650 if (!cfg_host->is_local) {
651 tst = ADMCFGNOTSUPPORTED;
654 /* set mode; not using bosserver because may not have necessary creds */
658 /* set no-authentication flag */
659 int fd = open(AFSDIR_SERVER_NOAUTH_FILEPATH,
660 O_CREAT | O_TRUNC | O_RDWR, 0666);
665 if (errno == EACCES) {
668 tst = ADMCFGHOSTSETNOAUTHFAILED;
672 /* clear no-authentication flag */
673 if (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH)) {
674 if (errno != ENOENT) {
675 if (errno == EACCES) {
678 tst = ADMCFGHOSTSETNOAUTHFAILED;
686 /* indicate failure */
697 * cfgutil_Sleep() -- put thread to sleep for specified number of seconds.
700 cfgutil_Sleep(unsigned sec)
705 time_t timeStart = time(NULL);
706 struct timeval sleeptime;
708 sleeptime.tv_sec = sec;
709 sleeptime.tv_usec = 0;
712 if (select(0, 0, 0, 0, &sleeptime) == 0) {
716 /* returned for reason other than timeout */
717 double cumSec = difftime(time(NULL), timeStart);
718 double remSec = (double)sec - cumSec;
723 sleeptime.tv_sec = ceil(remSec);
732 /* Service control functions */
734 /* define generic service error codes */
735 #define CFGUTIL_SVC_NOPRIV 1 /* insufficient privilege */
736 #define CFGUTIL_SVC_BAD 2 /* service not properly configured */
737 #define CFGUTIL_SVC_NOTREADY 3 /* service not ready to accept command */
738 #define CFGUTIL_SVC_TIMEOUT 4 /* timed out waiting for stop/start */
739 #define CFGUTIL_SVC_STATUSUNK 5 /* service status cannot be determined */
743 * ServiceCodeXlate() -- translate generic code to service-specific code
746 ServiceCodeXlate(LPCTSTR svcName, int code)
748 afs_status_t tst = ADMCFGNOTSUPPORTED;
750 if (!strcmp(svcName, AFSREG_CLT_SVC_NAME)) {
751 /* AFS client (CM) service code required */
753 case CFGUTIL_SVC_NOPRIV:
756 case CFGUTIL_SVC_BAD:
757 tst = ADMCFGCACHEMGRSERVICEBAD;
759 case CFGUTIL_SVC_NOTREADY:
760 tst = ADMCFGCACHEMGRSERVICENOTREADY;
762 case CFGUTIL_SVC_TIMEOUT:
763 tst = ADMCFGCACHEMGRSERVICETIMEOUT;
766 tst = ADMCFGCACHEMGRSERVICESTATUSUNK;
770 } else if (!strcmp(svcName, AFSREG_SVR_SVC_NAME)) {
771 /* AFS BOS control service code required */
773 case CFGUTIL_SVC_NOPRIV:
776 case CFGUTIL_SVC_BAD:
777 tst = ADMCFGBOSSERVERCTLSERVICEBAD;
779 case CFGUTIL_SVC_NOTREADY:
780 tst = ADMCFGBOSSERVERCTLSERVICENOTREADY;
782 case CFGUTIL_SVC_TIMEOUT:
783 tst = ADMCFGBOSSERVERCTLSERVICETIMEOUT;
786 tst = ADMCFGBOSSERVERCTLSERVICESTATUSUNK;
795 * cfgutil_WindowsServiceStart() -- Start a Windows service on local host.
797 * The value of timeout specifies the maximum time, in seconds, to wait
798 * for the service to be in the SERVICE_RUNNING state.
800 * If service was already started/starting then *wasRunning is true (1).
802 * RETURN CODES: 1 success, 0 failure (st indicates why)
805 cfgutil_WindowsServiceStart(LPCTSTR svcName, DWORD svcArgc, LPCTSTR * svcArgv,
806 unsigned timeout, short *wasRunning,
810 afs_status_t tst = 0;
811 SC_HANDLE scmHandle, svcHandle;
812 DWORD svcAccess = (SERVICE_START | SERVICE_QUERY_STATUS);
816 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
817 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
818 /* can't connect to SCM or can't open service */
819 DWORD status = GetLastError();
821 if (status == ERROR_ACCESS_DENIED) {
822 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
823 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
824 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
826 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
829 if (scmHandle != NULL) {
830 CloseServiceHandle(scmHandle);
834 /* service configured; attempt to start */
835 if (!StartService(svcHandle, svcArgc, svcArgv)) {
836 /* service start failed */
837 DWORD status = GetLastError();
839 if (status == ERROR_SERVICE_ALREADY_RUNNING) {
842 if (status == ERROR_ACCESS_DENIED) {
843 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
844 } else if (status == ERROR_SERVICE_DATABASE_LOCKED
845 || status == ERROR_SERVICE_DISABLED
846 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
847 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
849 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
854 /* wait for service to be in SERVICE_RUNNING state */
855 if (tst == 0 && timeout > 0) {
856 SERVICE_STATUS svcStatus;
857 time_t timeStart = time(NULL);
860 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
861 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
863 } else if (svcStatus.dwCurrentState == SERVICE_RUNNING) {
865 } else if (difftime(time(NULL), timeStart) > timeout) {
866 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
869 /* sleep a bit and check state again */
875 /* wait just a bit more because we're paranoid */
880 CloseServiceHandle(svcHandle);
881 CloseServiceHandle(scmHandle);
885 /* indicate failure */
896 * cfgutil_WindowsServiceStop() -- Stop a Windows service on local host.
898 * The value of timeout specifies the maximum time, in seconds, to wait
899 * for the service to be in the SERVICE_STOPPED state.
901 * If service was already stopped/stopping then *wasStopped is true (1).
903 * RETURN CODES: 1 success, 0 failure (st indicates why)
906 cfgutil_WindowsServiceStop(LPCTSTR svcName, unsigned timeout,
907 short *wasStopped, afs_status_p st)
910 afs_status_t tst = 0;
911 SC_HANDLE scmHandle, svcHandle;
912 DWORD svcAccess = (SERVICE_STOP | SERVICE_QUERY_STATUS);
916 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
917 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
918 /* can't connect to SCM or can't open service */
919 DWORD status = GetLastError();
921 if (status == ERROR_ACCESS_DENIED) {
922 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
923 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
924 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
926 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
929 if (scmHandle != NULL) {
930 CloseServiceHandle(scmHandle);
934 /* service configured; attempt to stop */
935 SERVICE_STATUS svcStatus;
937 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
938 /* service stop failed */
939 DWORD status = GetLastError();
941 if (status == ERROR_SERVICE_NOT_ACTIVE) {
944 if (status == ERROR_ACCESS_DENIED) {
945 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
946 } else if (status == ERROR_INVALID_SERVICE_CONTROL
947 || status == ERROR_SERVICE_CANNOT_ACCEPT_CTRL
948 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
949 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
951 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
956 /* wait for service to be in SERVICE_STOPPED state */
957 if (tst == 0 && timeout > 0) {
958 time_t timeStart = time(NULL);
961 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
962 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
964 } else if (svcStatus.dwCurrentState == SERVICE_STOPPED) {
966 } else if (difftime(time(NULL), timeStart) > timeout) {
967 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
970 /* sleep a bit and check state again */
976 /* wait just a bit more because we're paranoid */
981 CloseServiceHandle(svcHandle);
982 CloseServiceHandle(scmHandle);
986 /* indicate failure */
997 * cfgutil_WindowsServiceQuery() -- Query Windows service on local host.
999 * RETURN CODES: 1 success, 0 failure (st indicates why)
1002 cfgutil_WindowsServiceQuery(LPCTSTR svcName, DWORD * svcState,
1006 afs_status_t tst = 0;
1007 SC_HANDLE scmHandle, svcHandle;
1008 DWORD svcAccess = SERVICE_QUERY_STATUS;
1010 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
1011 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
1012 /* can't connect to SCM or can't open service */
1013 DWORD status = GetLastError();
1015 if (status == ERROR_ACCESS_DENIED) {
1016 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
1017 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
1018 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
1020 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1023 if (scmHandle != NULL) {
1024 CloseServiceHandle(scmHandle);
1028 /* service configured; determine service state */
1029 SERVICE_STATUS svcStatus;
1031 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
1032 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1034 *svcState = svcStatus.dwCurrentState;
1037 CloseServiceHandle(svcHandle);
1038 CloseServiceHandle(scmHandle);
1042 /* indicate failure */
1051 #endif /* AFS_NT40_ENV */