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 */