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>
18 #include <WINNT/afsreg.h>
19 #endif /* AFS_NT40_ENV */
27 #include <afs/afs_Admin.h>
28 #include <afs/afs_AdminErrors.h>
29 #include <afs/afs_bosAdmin.h>
30 #include <afs/afs_clientAdmin.h>
32 #include <afs/dirpath.h>
34 #include "cfginternal.h"
35 #include "../adminutil/afs_AdminInternal.h"
39 * cfgutil_HostHandleValidate() -- validate a host configuration handle
41 * RETURN CODES: 1 success, 0 failure
44 cfgutil_HostHandleValidate(const cfg_host_p cfg_host, afs_status_p st)
49 if (cfg_host == NULL) {
50 tst = ADMCFGHOSTHANDLENULL;
52 } else if (cfg_host->begin_magic != BEGIN_MAGIC
53 || cfg_host->end_magic != END_MAGIC) {
54 tst = ADMCFGHOSTHANDLEBADMAGIC;
56 } else if (cfg_host->is_valid == 0) {
57 tst = ADMCFGHOSTHANDLEINVALID;
59 } else if (cfg_host->hostName == NULL) {
60 tst = ADMCFGHOSTHANDLEHOSTNAMENULL;
62 } else if (cfg_host->cellHandle == NULL) {
63 tst = ADMCFGHOSTHANDLECELLHANDLENULL;
65 } else if (cfg_host->cellName == NULL) {
66 tst = ADMCFGHOSTHANDLECELLNAMENULL;
70 /* indicate failure */
81 * cfgutil_HostHandleBosInit() -- initialize bosserver handle in host
82 * configuration handle.
84 * RETURN CODES: 1 success, 0 failure
87 cfgutil_HostHandleBosInit(cfg_host_p cfg_host, afs_status_p st)
92 if (pthread_mutex_lock(&cfg_host->mutex)) {
95 if (cfg_host->bosHandle == NULL) {
96 /* initialize bosserver handle for host */
101 (cfg_host->cellHandle, cfg_host->hostName, &bosHandle,
103 cfg_host->bosHandle = bosHandle;
108 if (pthread_mutex_unlock(&cfg_host->mutex)) {
109 /* can only return one status; mutex failure is critical */
110 tst = ADMMUTEXUNLOCK;
115 /* indicate failure */
126 * cfgutil_HostHandleCellNameCompatible() -- determine if specified cell name
127 * is compatible with the cell name in the given cfg handle.
129 * RETURN CODES: 1 compatible, 0 not compatible
132 cfgutil_HostHandleCellNameCompatible(const cfg_host_p cfg_host,
133 const char *cellName)
137 if (*cfg_host->cellName == '\0') {
138 /* null cell handle; any cell name compatible by definition */
141 /* standard cell handle; compare cell names */
142 rc = (strcasecmp(cfg_host->cellName, cellName) == 0 ? 1 : 0);
149 * cfgutil_HostNameGetFull() -- return fully qualified version of specified
152 * Note: fullHostName is presumed to be a buffer of size MAXHOSTCHARS.
154 * RETURN CODES: 1 success, 0 failure
157 cfgutil_HostNameGetFull(const char *hostName, char *fullHostName,
161 afs_status_t tst = 0;
164 /* Note: gethostbyname() allocs hostent on a per-thread basis */
165 struct hostent *hentryp;
167 if ((hentryp = gethostbyname(hostName)) == NULL) {
168 tst = ADMCFGCANTRESOLVEHOSTNAME;
170 size_t hostNameLen = strlen(hostName);
171 char *fqName = hentryp->h_name;
173 /* verify that canonical name is an expansion of name specified */
174 if (strncasecmp(fqName, hostName, hostNameLen) != 0
175 || fqName[hostNameLen] != '.') {
176 /* canonical name not a direct expansion; consider aliases */
179 for (i = 0; hentryp->h_aliases[i] != NULL; i++) {
180 char *aliasName = hentryp->h_aliases[i];
181 if (strncasecmp(aliasName, hostName, hostNameLen) == 0
182 && aliasName[hostNameLen] == '.') {
183 /* found a direct exapansion of specified name */
190 if (strlen(fqName) > (MAXHOSTCHARS - 1)) {
191 tst = ADMCFGRESOLVEDHOSTNAMETOOLONG;
193 strcpy(fullHostName, fqName);
195 /* lower-case name for consistency */
196 _strlwr(fullHostName);
200 /* function not yet implemented for Unix */
201 tst = ADMCFGNOTSUPPORTED;
202 #endif /* AFS_NT40_ENV */
205 /* indicate failure */
216 * cfgutil_HostNameIsAlias() -- determine if specified host names
217 * are aliases (functionally equivalent).
219 * RETURN CODES: 1 success, 0 failure
222 cfgutil_HostNameIsAlias(const char *hostName1, const char *hostName2,
223 short *isAlias, afs_status_p st)
226 afs_status_t tst2, tst = 0;
227 int addrCount1, addrCount2;
228 afs_int32 *addrList1 = NULL, *addrList2 = NULL;
230 /* get all addrs for first host */
232 if (!cfgutil_HostAddressFetchAll
233 (hostName1, &addrCount1, &addrList1, &tst2)) {
237 /* get all addrs for second host */
240 if (!cfgutil_HostAddressFetchAll
241 (hostName2, &addrCount2, &addrList2, &tst2)) {
250 /* compare lists looking for a match */
257 for (i = 0; i < addrCount1; i++) {
258 for (j = 0; j < addrCount2; j++) {
259 if (addrList1[i] == addrList2[j]) {
276 /* indicate failure */
287 * cfgutil_HostNameIsLocal() -- determine if the specified host name is
288 * equivalent to (is an alias for) the standard host name for the
289 * machine on which this process is running.
291 * RETURN CODES: 1 success, 0 failure
294 cfgutil_HostNameIsLocal(const char *hostName, short *isLocal, afs_status_p st)
297 afs_status_t tst2, tst = 0;
298 char localName[MAXHOSTCHARS];
300 if (gethostname(localName, MAXHOSTCHARS)) {
301 /* failed to lookup local name */
302 tst = ADMCANTGETLOCALNAME;
303 } else if (!cfgutil_HostNameIsAlias(hostName, localName, isLocal, &tst2)) {
308 /* indicate failure */
319 * cfgutil_HostNameGetCellServDbAlias() -- Get alias for given host name
320 * as listed in the server CellServDB on the specified host. If no
321 * alias is found then hostNameAlias is set to the empty string.
323 * Note: hostNameAlias is presumed to be a buffer of size MAXHOSTCHARS.
325 * RETURN CODES: 1 success, 0 failure
328 cfgutil_HostNameGetCellServDbAlias(const char *fsDbHost, const char *hostName,
329 char *hostNameAlias, afs_status_p st)
332 afs_status_t tst2, tst = 0;
336 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
339 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
344 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
347 short dbhostDone = 0;
348 short dbhostFound = 0;
350 while (!dbhostDone) {
353 if (!bos_HostGetNext(dbIter, hostNameAlias, &tst2)) {
354 /* no more entries (or failure) */
355 if (tst2 != ADMITERATORDONE) {
361 if (!cfgutil_HostNameIsAlias
362 (hostName, hostNameAlias, &isAlias, &tst2)) {
366 } else if (isAlias) {
373 *hostNameAlias = '\0';
376 if (!bos_HostGetDone(dbIter, &tst2)) {
381 if (!bos_ServerClose(bosHandle, &tst2)) {
386 if (!afsclient_CellClose(cellHandle, &tst2)) {
392 /* indicate failure */
403 * cfgutil_HostNameGetAddressString() -- Get IP address for specified host in
404 * in the canonical string form.
406 * Returns pointer to a per-thread buffer; do not deallocate.
409 cfgutil_HostNameGetAddressString(const char *hostName, const char **hostAddr,
413 afs_status_t tst2, tst = 0;
415 afs_int32 *addrList = NULL;
417 /* get address list for host */
419 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
423 /* convert first (canonical) address to string */
429 ina.s_addr = htonl(addrList[0]);
430 if ((inaString = inet_ntoa(ina)) == NULL) {
431 /* should never happen */
432 tst = ADMCFGCANTRESOLVEHOSTNAME;
434 *hostAddr = inaString;
443 /* indicate failure */
454 * cfgutil_HostAddressFetchAll() -- get allocated list of all known
455 * addresses for specified host.
457 * Note: upon success, *addrList is an address array in host byte order.
459 * RETURN CODES: 1 success, 0 failure
462 cfgutil_HostAddressFetchAll(const char *hostName, int *addrCount,
463 afs_int32 ** addrList, afs_status_p st)
466 afs_status_t tst = 0;
468 afs_int32 *aList = NULL;
471 /* Note: gethostbyname() allocs hostent on a per-thread basis */
472 struct hostent *hentryp;
474 if ((hentryp = gethostbyname(hostName)) == NULL) {
475 tst = ADMCFGCANTRESOLVEHOSTNAME;
479 /* assuming IPv4 addrs returned */
480 for (i = 0; hentryp->h_addr_list[i] != NULL; i++);
483 if ((aList = malloc(aCount * sizeof(afs_int32))) == NULL) {
486 for (i = 0; i < aCount; i++) {
488 memcpy((void *)&hostAddr, (void *)hentryp->h_addr_list[i],
490 aList[i] = ntohl(hostAddr);
495 /* function not yet implemented for Unix */
496 tst = ADMCFGNOTSUPPORTED;
497 #endif /* AFS_NT40_ENV */
504 /* indicate failure */
515 * cfgutil_HostAddressIsValid() -- determine if address is a valid address
516 * for the named host.
518 * Note: hostAddr must be specified in host byte order
520 * RETURN CODES: 1 success, 0 failure
523 cfgutil_HostAddressIsValid(const char *hostName, int hostAddr, short *isValid,
527 afs_status_t tst2, tst = 0;
529 afs_int32 *addrList = NULL;
533 /* get all addrs for host */
535 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
539 /* search list looking for match */
544 for (i = 0; i < addrCount; i++) {
545 if (addrList[i] == hostAddr) {
557 /* indicate failure */
568 * cfgutil_CleanDirectory() -- remove all files from specified directory;
569 * function is NOT recursive.
571 * RETURN CODES: 1 success, 0 failure
574 cfgutil_CleanDirectory(const char *dirName, afs_status_p st)
577 afs_status_t tst = 0;
580 struct dirent *entryp;
581 char dirfile[MAXPATHLEN];
583 if ((dirp = opendir(dirName)) == NULL) {
584 /* cannot open directory */
585 if (errno == EACCES) {
588 /* otherwise assume directory does not exist, which is OK */
590 while ((entryp = readdir(dirp)) != NULL) {
591 /* remove file (except "." and "..") */
592 if (strcmp(entryp->d_name, ".") && strcmp(entryp->d_name, "..")) {
593 sprintf(dirfile, "%s/%s", dirName, entryp->d_name);
594 if (unlink(dirfile)) {
596 if (errno == EACCES) {
600 /* otherwise assume file removed by someone else or
601 * that file is a directory, which is OK.
607 (void)closedir(dirp);
611 /* indicate failure */
622 * cfgutil_HostSetNoAuthFlag() -- set AFS server authentication flag on host
624 * RETURN CODES: 1 success, 0 failure (st indicates why)
627 cfgutil_HostSetNoAuthFlag(const cfg_host_p cfg_host, short noAuth,
631 afs_status_t tst = 0;
633 /* remote configuration not yet supported in this function */
635 if (!cfg_host->is_local) {
636 tst = ADMCFGNOTSUPPORTED;
639 /* set mode; not using bosserver because may not have necessary creds */
643 /* set no-authentication flag */
644 int fd = open(AFSDIR_SERVER_NOAUTH_FILEPATH,
645 O_CREAT | O_TRUNC | O_RDWR, 0666);
650 if (errno == EACCES) {
653 tst = ADMCFGHOSTSETNOAUTHFAILED;
657 /* clear no-authentication flag */
658 if (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH)) {
659 if (errno != ENOENT) {
660 if (errno == EACCES) {
663 tst = ADMCFGHOSTSETNOAUTHFAILED;
671 /* indicate failure */
682 * cfgutil_Sleep() -- put thread to sleep for specified number of seconds.
685 cfgutil_Sleep(unsigned sec)
690 time_t timeStart = time(NULL);
691 struct timeval sleeptime;
693 sleeptime.tv_sec = sec;
694 sleeptime.tv_usec = 0;
697 if (select(0, 0, 0, 0, &sleeptime) == 0) {
701 /* returned for reason other than timeout */
702 double cumSec = difftime(time(NULL), timeStart);
703 double remSec = (double)sec - cumSec;
708 sleeptime.tv_sec = ceil(remSec);
717 /* Service control functions */
719 /* define generic service error codes */
720 #define CFGUTIL_SVC_NOPRIV 1 /* insufficient privilege */
721 #define CFGUTIL_SVC_BAD 2 /* service not properly configured */
722 #define CFGUTIL_SVC_NOTREADY 3 /* service not ready to accept command */
723 #define CFGUTIL_SVC_TIMEOUT 4 /* timed out waiting for stop/start */
724 #define CFGUTIL_SVC_STATUSUNK 5 /* service status cannot be determined */
728 * ServiceCodeXlate() -- translate generic code to service-specific code
731 ServiceCodeXlate(LPCTSTR svcName, int code)
733 afs_status_t tst = ADMCFGNOTSUPPORTED;
735 if (!strcmp(svcName, AFSREG_CLT_SVC_NAME)) {
736 /* AFS client (CM) service code required */
738 case CFGUTIL_SVC_NOPRIV:
741 case CFGUTIL_SVC_BAD:
742 tst = ADMCFGCACHEMGRSERVICEBAD;
744 case CFGUTIL_SVC_NOTREADY:
745 tst = ADMCFGCACHEMGRSERVICENOTREADY;
747 case CFGUTIL_SVC_TIMEOUT:
748 tst = ADMCFGCACHEMGRSERVICETIMEOUT;
751 tst = ADMCFGCACHEMGRSERVICESTATUSUNK;
755 } else if (!strcmp(svcName, AFSREG_SVR_SVC_NAME)) {
756 /* AFS BOS control service code required */
758 case CFGUTIL_SVC_NOPRIV:
761 case CFGUTIL_SVC_BAD:
762 tst = ADMCFGBOSSERVERCTLSERVICEBAD;
764 case CFGUTIL_SVC_NOTREADY:
765 tst = ADMCFGBOSSERVERCTLSERVICENOTREADY;
767 case CFGUTIL_SVC_TIMEOUT:
768 tst = ADMCFGBOSSERVERCTLSERVICETIMEOUT;
771 tst = ADMCFGBOSSERVERCTLSERVICESTATUSUNK;
780 * cfgutil_WindowsServiceStart() -- Start a Windows service on local host.
782 * The value of timeout specifies the maximum time, in seconds, to wait
783 * for the service to be in the SERVICE_RUNNING state.
785 * If service was already started/starting then *wasRunning is true (1).
787 * RETURN CODES: 1 success, 0 failure (st indicates why)
790 cfgutil_WindowsServiceStart(LPCTSTR svcName, DWORD svcArgc, LPCTSTR * svcArgv,
791 unsigned timeout, short *wasRunning,
795 afs_status_t tst = 0;
796 SC_HANDLE scmHandle, svcHandle;
797 DWORD svcAccess = (SERVICE_START | SERVICE_QUERY_STATUS);
801 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
802 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
803 /* can't connect to SCM or can't open service */
804 DWORD status = GetLastError();
806 if (status == ERROR_ACCESS_DENIED) {
807 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
808 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
809 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
811 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
814 if (scmHandle != NULL) {
815 CloseServiceHandle(scmHandle);
819 /* service configured; attempt to start */
820 if (!StartService(svcHandle, svcArgc, svcArgv)) {
821 /* service start failed */
822 DWORD status = GetLastError();
824 if (status == ERROR_SERVICE_ALREADY_RUNNING) {
827 if (status == ERROR_ACCESS_DENIED) {
828 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
829 } else if (status == ERROR_SERVICE_DATABASE_LOCKED
830 || status == ERROR_SERVICE_DISABLED
831 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
832 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
834 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
839 /* wait for service to be in SERVICE_RUNNING state */
840 if (tst == 0 && timeout > 0) {
841 SERVICE_STATUS svcStatus;
842 time_t timeStart = time(NULL);
845 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
846 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
848 } else if (svcStatus.dwCurrentState == SERVICE_RUNNING) {
850 } else if (difftime(time(NULL), timeStart) > timeout) {
851 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
854 /* sleep a bit and check state again */
860 /* wait just a bit more because we're paranoid */
865 CloseServiceHandle(svcHandle);
866 CloseServiceHandle(scmHandle);
870 /* indicate failure */
881 * cfgutil_WindowsServiceStop() -- Stop a Windows service on local host.
883 * The value of timeout specifies the maximum time, in seconds, to wait
884 * for the service to be in the SERVICE_STOPPED state.
886 * If service was already stopped/stopping then *wasStopped is true (1).
888 * RETURN CODES: 1 success, 0 failure (st indicates why)
891 cfgutil_WindowsServiceStop(LPCTSTR svcName, unsigned timeout,
892 short *wasStopped, afs_status_p st)
895 afs_status_t tst = 0;
896 SC_HANDLE scmHandle, svcHandle;
897 DWORD svcAccess = (SERVICE_STOP | SERVICE_QUERY_STATUS);
901 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
902 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
903 /* can't connect to SCM or can't open service */
904 DWORD status = GetLastError();
906 if (status == ERROR_ACCESS_DENIED) {
907 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
908 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
909 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
911 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
914 if (scmHandle != NULL) {
915 CloseServiceHandle(scmHandle);
919 /* service configured; attempt to stop */
920 SERVICE_STATUS svcStatus;
922 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
923 /* service stop failed */
924 DWORD status = GetLastError();
926 if (status == ERROR_SERVICE_NOT_ACTIVE) {
929 if (status == ERROR_ACCESS_DENIED) {
930 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
931 } else if (status == ERROR_INVALID_SERVICE_CONTROL
932 || status == ERROR_SERVICE_CANNOT_ACCEPT_CTRL
933 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
934 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
936 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
941 /* wait for service to be in SERVICE_STOPPED state */
942 if (tst == 0 && timeout > 0) {
943 time_t timeStart = time(NULL);
946 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
947 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
949 } else if (svcStatus.dwCurrentState == SERVICE_STOPPED) {
951 } else if (difftime(time(NULL), timeStart) > timeout) {
952 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
955 /* sleep a bit and check state again */
961 /* wait just a bit more because we're paranoid */
966 CloseServiceHandle(svcHandle);
967 CloseServiceHandle(scmHandle);
971 /* indicate failure */
982 * cfgutil_WindowsServiceQuery() -- Query Windows service on local host.
984 * RETURN CODES: 1 success, 0 failure (st indicates why)
987 cfgutil_WindowsServiceQuery(LPCTSTR svcName, DWORD * svcState,
991 afs_status_t tst = 0;
992 SC_HANDLE scmHandle, svcHandle;
993 DWORD svcAccess = SERVICE_QUERY_STATUS;
995 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
996 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
997 /* can't connect to SCM or can't open service */
998 DWORD status = GetLastError();
1000 if (status == ERROR_ACCESS_DENIED) {
1001 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
1002 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
1003 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
1005 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1008 if (scmHandle != NULL) {
1009 CloseServiceHandle(scmHandle);
1013 /* service configured; determine service state */
1014 SERVICE_STATUS svcStatus;
1016 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
1017 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1019 *svcState = svcStatus.dwCurrentState;
1022 CloseServiceHandle(svcHandle);
1023 CloseServiceHandle(scmHandle);
1027 /* indicate failure */
1036 #endif /* AFS_NT40_ENV */