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>
29 #include <afs/dirent.h>
30 #include <WINNT/afsreg.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
38 #include <sys/param.h>
39 #endif /* AFS_NT40_ENV */
43 #include <afs/afs_Admin.h>
44 #include <afs/afs_AdminErrors.h>
45 #include <afs/afs_bosAdmin.h>
46 #include <afs/afs_clientAdmin.h>
48 #include <afs/dirpath.h>
50 #include "cfginternal.h"
51 #include "../adminutil/afs_AdminInternal.h"
55 * cfgutil_HostHandleValidate() -- validate a host configuration handle
57 * RETURN CODES: 1 success, 0 failure
60 cfgutil_HostHandleValidate(const cfg_host_p cfg_host, afs_status_p st)
65 if (cfg_host == NULL) {
66 tst = ADMCFGHOSTHANDLENULL;
68 } else if (cfg_host->begin_magic != BEGIN_MAGIC
69 || cfg_host->end_magic != END_MAGIC) {
70 tst = ADMCFGHOSTHANDLEBADMAGIC;
72 } else if (cfg_host->is_valid == 0) {
73 tst = ADMCFGHOSTHANDLEINVALID;
75 } else if (cfg_host->hostName == NULL) {
76 tst = ADMCFGHOSTHANDLEHOSTNAMENULL;
78 } else if (cfg_host->cellHandle == NULL) {
79 tst = ADMCFGHOSTHANDLECELLHANDLENULL;
81 } else if (cfg_host->cellName == NULL) {
82 tst = ADMCFGHOSTHANDLECELLNAMENULL;
86 /* indicate failure */
97 * cfgutil_HostHandleBosInit() -- initialize bosserver handle in host
98 * configuration handle.
100 * RETURN CODES: 1 success, 0 failure
103 cfgutil_HostHandleBosInit(cfg_host_p cfg_host, afs_status_p st)
106 afs_status_t tst = 0;
108 if (pthread_mutex_lock(&cfg_host->mutex)) {
111 if (cfg_host->bosHandle == NULL) {
112 /* initialize bosserver handle for host */
117 (cfg_host->cellHandle, cfg_host->hostName, &bosHandle,
119 cfg_host->bosHandle = bosHandle;
124 if (pthread_mutex_unlock(&cfg_host->mutex)) {
125 /* can only return one status; mutex failure is critical */
126 tst = ADMMUTEXUNLOCK;
131 /* indicate failure */
142 * cfgutil_HostHandleCellNameCompatible() -- determine if specified cell name
143 * is compatible with the cell name in the given cfg handle.
145 * RETURN CODES: 1 compatible, 0 not compatible
148 cfgutil_HostHandleCellNameCompatible(const cfg_host_p cfg_host,
149 const char *cellName)
153 if (*cfg_host->cellName == '\0') {
154 /* null cell handle; any cell name compatible by definition */
157 /* standard cell handle; compare cell names */
158 rc = (strcasecmp(cfg_host->cellName, cellName) == 0 ? 1 : 0);
165 * cfgutil_HostNameGetFull() -- return fully qualified version of specified
168 * Note: fullHostName is presumed to be a buffer of size MAXHOSTCHARS.
170 * RETURN CODES: 1 success, 0 failure
173 cfgutil_HostNameGetFull(const char *hostName, char *fullHostName,
177 afs_status_t tst = 0;
180 /* Note: gethostbyname() allocs hostent on a per-thread basis */
181 struct hostent *hentryp;
183 if ((hentryp = gethostbyname(hostName)) == NULL) {
184 tst = ADMCFGCANTRESOLVEHOSTNAME;
186 size_t hostNameLen = strlen(hostName);
187 char *fqName = hentryp->h_name;
189 /* verify that canonical name is an expansion of name specified */
190 if (strncasecmp(fqName, hostName, hostNameLen) != 0
191 || fqName[hostNameLen] != '.') {
192 /* canonical name not a direct expansion; consider aliases */
195 for (i = 0; hentryp->h_aliases[i] != NULL; i++) {
196 char *aliasName = hentryp->h_aliases[i];
197 if (strncasecmp(aliasName, hostName, hostNameLen) == 0
198 && aliasName[hostNameLen] == '.') {
199 /* found a direct exapansion of specified name */
206 if (strlen(fqName) > (MAXHOSTCHARS - 1)) {
207 tst = ADMCFGRESOLVEDHOSTNAMETOOLONG;
209 strcpy(fullHostName, fqName);
211 /* lower-case name for consistency */
212 _strlwr(fullHostName);
216 /* function not yet implemented for Unix */
217 tst = ADMCFGNOTSUPPORTED;
218 #endif /* AFS_NT40_ENV */
221 /* indicate failure */
232 * cfgutil_HostNameIsAlias() -- determine if specified host names
233 * are aliases (functionally equivalent).
235 * RETURN CODES: 1 success, 0 failure
238 cfgutil_HostNameIsAlias(const char *hostName1, const char *hostName2,
239 short *isAlias, afs_status_p st)
242 afs_status_t tst2, tst = 0;
243 int addrCount1, addrCount2;
244 afs_int32 *addrList1 = NULL, *addrList2 = NULL;
246 /* get all addrs for first host */
248 if (!cfgutil_HostAddressFetchAll
249 (hostName1, &addrCount1, &addrList1, &tst2)) {
253 /* get all addrs for second host */
256 if (!cfgutil_HostAddressFetchAll
257 (hostName2, &addrCount2, &addrList2, &tst2)) {
266 /* compare lists looking for a match */
273 for (i = 0; i < addrCount1; i++) {
274 for (j = 0; j < addrCount2; j++) {
275 if (addrList1[i] == addrList2[j]) {
292 /* indicate failure */
303 * cfgutil_HostNameIsLocal() -- determine if the specified host name is
304 * equivalent to (is an alias for) the standard host name for the
305 * machine on which this process is running.
307 * RETURN CODES: 1 success, 0 failure
310 cfgutil_HostNameIsLocal(const char *hostName, short *isLocal, afs_status_p st)
313 afs_status_t tst2, tst = 0;
314 char localName[MAXHOSTCHARS];
316 if (gethostname(localName, MAXHOSTCHARS)) {
317 /* failed to lookup local name */
318 tst = ADMCANTGETLOCALNAME;
319 } else if (!cfgutil_HostNameIsAlias(hostName, localName, isLocal, &tst2)) {
324 /* indicate failure */
335 * cfgutil_HostNameGetCellServDbAlias() -- Get alias for given host name
336 * as listed in the server CellServDB on the specified host. If no
337 * alias is found then hostNameAlias is set to the empty string.
339 * Note: hostNameAlias is presumed to be a buffer of size MAXHOSTCHARS.
341 * RETURN CODES: 1 success, 0 failure
344 cfgutil_HostNameGetCellServDbAlias(const char *fsDbHost, const char *hostName,
345 char *hostNameAlias, afs_status_p st)
348 afs_status_t tst2, tst = 0;
352 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
355 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
360 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
363 short dbhostDone = 0;
364 short dbhostFound = 0;
366 while (!dbhostDone) {
369 if (!bos_HostGetNext(dbIter, hostNameAlias, &tst2)) {
370 /* no more entries (or failure) */
371 if (tst2 != ADMITERATORDONE) {
377 if (!cfgutil_HostNameIsAlias
378 (hostName, hostNameAlias, &isAlias, &tst2)) {
382 } else if (isAlias) {
389 *hostNameAlias = '\0';
392 if (!bos_HostGetDone(dbIter, &tst2)) {
397 if (!bos_ServerClose(bosHandle, &tst2)) {
402 if (!afsclient_CellClose(cellHandle, &tst2)) {
408 /* indicate failure */
419 * cfgutil_HostNameGetAddressString() -- Get IP address for specified host in
420 * in the canonical string form.
422 * Returns pointer to a per-thread buffer; do not deallocate.
425 cfgutil_HostNameGetAddressString(const char *hostName, const char **hostAddr,
429 afs_status_t tst2, tst = 0;
431 afs_int32 *addrList = NULL;
433 /* get address list for host */
435 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
439 /* convert first (canonical) address to string */
445 ina.s_addr = htonl(addrList[0]);
446 if ((inaString = inet_ntoa(ina)) == NULL) {
447 /* should never happen */
448 tst = ADMCFGCANTRESOLVEHOSTNAME;
450 *hostAddr = inaString;
459 /* indicate failure */
470 * cfgutil_HostAddressFetchAll() -- get allocated list of all known
471 * addresses for specified host.
473 * Note: upon success, *addrList is an address array in host byte order.
475 * RETURN CODES: 1 success, 0 failure
478 cfgutil_HostAddressFetchAll(const char *hostName, int *addrCount,
479 afs_int32 ** addrList, afs_status_p st)
482 afs_status_t tst = 0;
484 afs_int32 *aList = NULL;
487 /* Note: gethostbyname() allocs hostent on a per-thread basis */
488 struct hostent *hentryp;
490 if ((hentryp = gethostbyname(hostName)) == NULL) {
491 tst = ADMCFGCANTRESOLVEHOSTNAME;
495 /* assuming IPv4 addrs returned */
496 for (i = 0; hentryp->h_addr_list[i] != NULL; i++);
500 (afs_int32 *) malloc(aCount * sizeof(afs_int32))) == NULL) {
503 for (i = 0; i < aCount; i++) {
505 memcpy((void *)&hostAddr, (void *)hentryp->h_addr_list[i],
507 aList[i] = ntohl(hostAddr);
512 /* function not yet implemented for Unix */
513 tst = ADMCFGNOTSUPPORTED;
514 #endif /* AFS_NT40_ENV */
521 /* indicate failure */
532 * cfgutil_HostAddressIsValid() -- determine if address is a valid address
533 * for the named host.
535 * Note: hostAddr must be specified in host byte order
537 * RETURN CODES: 1 success, 0 failure
540 cfgutil_HostAddressIsValid(const char *hostName, int hostAddr, short *isValid,
544 afs_status_t tst2, tst = 0;
546 afs_int32 *addrList = NULL;
550 /* get all addrs for host */
552 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
556 /* search list looking for match */
561 for (i = 0; i < addrCount; i++) {
562 if (addrList[i] == hostAddr) {
574 /* indicate failure */
585 * cfgutil_CleanDirectory() -- remove all files from specified directory;
586 * function is NOT recursive.
588 * RETURN CODES: 1 success, 0 failure
591 cfgutil_CleanDirectory(const char *dirName, afs_status_p st)
594 afs_status_t tst = 0;
597 struct dirent *entryp;
598 char dirfile[MAXPATHLEN];
600 if ((dirp = opendir(dirName)) == NULL) {
601 /* cannot open directory */
602 if (errno == EACCES) {
605 /* otherwise assume directory does not exist, which is OK */
607 while ((entryp = readdir(dirp)) != NULL) {
608 /* remove file (except "." and "..") */
609 if (strcmp(entryp->d_name, ".") && strcmp(entryp->d_name, "..")) {
610 sprintf(dirfile, "%s/%s", dirName, entryp->d_name);
611 if (unlink(dirfile)) {
613 if (errno == EACCES) {
617 /* otherwise assume file removed by someone else or
618 * that file is a directory, which is OK.
624 (void)closedir(dirp);
628 /* indicate failure */
639 * cfgutil_HostSetNoAuthFlag() -- set AFS server authentication flag on host
641 * RETURN CODES: 1 success, 0 failure (st indicates why)
644 cfgutil_HostSetNoAuthFlag(const cfg_host_p cfg_host, short noAuth,
648 afs_status_t tst = 0;
650 /* remote configuration not yet supported in this function */
652 if (!cfg_host->is_local) {
653 tst = ADMCFGNOTSUPPORTED;
656 /* set mode; not using bosserver because may not have necessary creds */
660 /* set no-authentication flag */
661 int fd = open(AFSDIR_SERVER_NOAUTH_FILEPATH,
662 O_CREAT | O_TRUNC | O_RDWR, 0666);
667 if (errno == EACCES) {
670 tst = ADMCFGHOSTSETNOAUTHFAILED;
674 /* clear no-authentication flag */
675 if (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH)) {
676 if (errno != ENOENT) {
677 if (errno == EACCES) {
680 tst = ADMCFGHOSTSETNOAUTHFAILED;
688 /* indicate failure */
699 * cfgutil_Sleep() -- put thread to sleep for specified number of seconds.
702 cfgutil_Sleep(unsigned sec)
707 time_t timeStart = time(NULL);
708 struct timeval sleeptime;
710 sleeptime.tv_sec = sec;
711 sleeptime.tv_usec = 0;
714 if (select(0, 0, 0, 0, &sleeptime) == 0) {
718 /* returned for reason other than timeout */
719 double cumSec = difftime(time(NULL), timeStart);
720 double remSec = (double)sec - cumSec;
725 sleeptime.tv_sec = ceil(remSec);
734 /* Service control functions */
736 /* define generic service error codes */
737 #define CFGUTIL_SVC_NOPRIV 1 /* insufficient privilege */
738 #define CFGUTIL_SVC_BAD 2 /* service not properly configured */
739 #define CFGUTIL_SVC_NOTREADY 3 /* service not ready to accept command */
740 #define CFGUTIL_SVC_TIMEOUT 4 /* timed out waiting for stop/start */
741 #define CFGUTIL_SVC_STATUSUNK 5 /* service status cannot be determined */
745 * ServiceCodeXlate() -- translate generic code to service-specific code
748 ServiceCodeXlate(LPCTSTR svcName, int code)
750 afs_status_t tst = ADMCFGNOTSUPPORTED;
752 if (!strcmp(svcName, AFSREG_CLT_SVC_NAME)) {
753 /* AFS client (CM) service code required */
755 case CFGUTIL_SVC_NOPRIV:
758 case CFGUTIL_SVC_BAD:
759 tst = ADMCFGCACHEMGRSERVICEBAD;
761 case CFGUTIL_SVC_NOTREADY:
762 tst = ADMCFGCACHEMGRSERVICENOTREADY;
764 case CFGUTIL_SVC_TIMEOUT:
765 tst = ADMCFGCACHEMGRSERVICETIMEOUT;
768 tst = ADMCFGCACHEMGRSERVICESTATUSUNK;
772 } else if (!strcmp(svcName, AFSREG_SVR_SVC_NAME)) {
773 /* AFS BOS control service code required */
775 case CFGUTIL_SVC_NOPRIV:
778 case CFGUTIL_SVC_BAD:
779 tst = ADMCFGBOSSERVERCTLSERVICEBAD;
781 case CFGUTIL_SVC_NOTREADY:
782 tst = ADMCFGBOSSERVERCTLSERVICENOTREADY;
784 case CFGUTIL_SVC_TIMEOUT:
785 tst = ADMCFGBOSSERVERCTLSERVICETIMEOUT;
788 tst = ADMCFGBOSSERVERCTLSERVICESTATUSUNK;
797 * cfgutil_WindowsServiceStart() -- Start a Windows service on local host.
799 * The value of timeout specifies the maximum time, in seconds, to wait
800 * for the service to be in the SERVICE_RUNNING state.
802 * If service was already started/starting then *wasRunning is true (1).
804 * RETURN CODES: 1 success, 0 failure (st indicates why)
807 cfgutil_WindowsServiceStart(LPCTSTR svcName, DWORD svcArgc, LPCTSTR * svcArgv,
808 unsigned timeout, short *wasRunning,
812 afs_status_t tst = 0;
813 SC_HANDLE scmHandle, svcHandle;
814 DWORD svcAccess = (SERVICE_START | SERVICE_QUERY_STATUS);
818 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
819 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
820 /* can't connect to SCM or can't open service */
821 DWORD status = GetLastError();
823 if (status == ERROR_ACCESS_DENIED) {
824 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
825 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
826 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
828 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
831 if (scmHandle != NULL) {
832 CloseServiceHandle(scmHandle);
836 /* service configured; attempt to start */
837 if (!StartService(svcHandle, svcArgc, svcArgv)) {
838 /* service start failed */
839 DWORD status = GetLastError();
841 if (status == ERROR_SERVICE_ALREADY_RUNNING) {
844 if (status == ERROR_ACCESS_DENIED) {
845 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
846 } else if (status == ERROR_SERVICE_DATABASE_LOCKED
847 || status == ERROR_SERVICE_DISABLED
848 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
849 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
851 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
856 /* wait for service to be in SERVICE_RUNNING state */
857 if (tst == 0 && timeout > 0) {
858 SERVICE_STATUS svcStatus;
859 time_t timeStart = time(NULL);
862 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
863 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
865 } else if (svcStatus.dwCurrentState == SERVICE_RUNNING) {
867 } else if (difftime(time(NULL), timeStart) > timeout) {
868 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
871 /* sleep a bit and check state again */
877 /* wait just a bit more because we're paranoid */
882 CloseServiceHandle(svcHandle);
883 CloseServiceHandle(scmHandle);
887 /* indicate failure */
898 * cfgutil_WindowsServiceStop() -- Stop a Windows service on local host.
900 * The value of timeout specifies the maximum time, in seconds, to wait
901 * for the service to be in the SERVICE_STOPPED state.
903 * If service was already stopped/stopping then *wasStopped is true (1).
905 * RETURN CODES: 1 success, 0 failure (st indicates why)
908 cfgutil_WindowsServiceStop(LPCTSTR svcName, unsigned timeout,
909 short *wasStopped, afs_status_p st)
912 afs_status_t tst = 0;
913 SC_HANDLE scmHandle, svcHandle;
914 DWORD svcAccess = (SERVICE_STOP | SERVICE_QUERY_STATUS);
918 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
919 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
920 /* can't connect to SCM or can't open service */
921 DWORD status = GetLastError();
923 if (status == ERROR_ACCESS_DENIED) {
924 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
925 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
926 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
928 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
931 if (scmHandle != NULL) {
932 CloseServiceHandle(scmHandle);
936 /* service configured; attempt to stop */
937 SERVICE_STATUS svcStatus;
939 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
940 /* service stop failed */
941 DWORD status = GetLastError();
943 if (status == ERROR_SERVICE_NOT_ACTIVE) {
946 if (status == ERROR_ACCESS_DENIED) {
947 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
948 } else if (status == ERROR_INVALID_SERVICE_CONTROL
949 || status == ERROR_SERVICE_CANNOT_ACCEPT_CTRL
950 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
951 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
953 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
958 /* wait for service to be in SERVICE_STOPPED state */
959 if (tst == 0 && timeout > 0) {
960 time_t timeStart = time(NULL);
963 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
964 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
966 } else if (svcStatus.dwCurrentState == SERVICE_STOPPED) {
968 } else if (difftime(time(NULL), timeStart) > timeout) {
969 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
972 /* sleep a bit and check state again */
978 /* wait just a bit more because we're paranoid */
983 CloseServiceHandle(svcHandle);
984 CloseServiceHandle(scmHandle);
988 /* indicate failure */
999 * cfgutil_WindowsServiceQuery() -- Query Windows service on local host.
1001 * RETURN CODES: 1 success, 0 failure (st indicates why)
1004 cfgutil_WindowsServiceQuery(LPCTSTR svcName, DWORD * svcState,
1008 afs_status_t tst = 0;
1009 SC_HANDLE scmHandle, svcHandle;
1010 DWORD svcAccess = SERVICE_QUERY_STATUS;
1012 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
1013 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
1014 /* can't connect to SCM or can't open service */
1015 DWORD status = GetLastError();
1017 if (status == ERROR_ACCESS_DENIED) {
1018 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
1019 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
1020 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
1022 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1025 if (scmHandle != NULL) {
1026 CloseServiceHandle(scmHandle);
1030 /* service configured; determine service state */
1031 SERVICE_STATUS svcStatus;
1033 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
1034 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1036 *svcState = svcStatus.dwCurrentState;
1039 CloseServiceHandle(svcHandle);
1040 CloseServiceHandle(scmHandle);
1044 /* indicate failure */
1053 #endif /* AFS_NT40_ENV */