Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libadmin / cfg / cfgclient.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10 /* This file implements configuration functions in the following categories:
11 * cfg_Client*() - perform minimally necessary client configuration.
12 */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #include <roken.h>
19
20 #include <rx/rx.h>
21 #include <rx/rxstat.h>
22 #include <afs/afs_Admin.h>
23 #include <afs/afs_AdminErrors.h>
24 #include <afs/afs_utilAdmin.h>
25 #include <afs/dirpath.h>
26 #include <afs/cellconfig.h>
27 #include <afs/kautils.h>
28
29 #ifdef AFS_NT40_ENV
30 #include <windows.h>
31 #include <WINNT/afsreg.h>
32 #include <WINNT/afssw.h>
33 #include <cellservdb.h>
34 #endif
35
36 #include "cfginternal.h"
37 #include "afs_cfgAdmin.h"
38
39
40 /* Local declarations and definitions */
41
42 #define CSDB_OP_ADD 0 /* add a client CellServDB entry */
43 #define CSDB_OP_REM 1 /* remove a client CellServDB entry */
44
45 static int
46 ClientCellServDbUpdate(int updateOp, void *hostHandle, const char *cellName,
47 const char *dbentry, afs_status_p st);
48
49 static int
50 CacheManagerStart(unsigned timeout, afs_status_p st);
51
52 static int
53 CacheManagerStop(unsigned timeout, afs_status_p st);
54
55
56
57
58 /* ---------------- Exported AFS Client functions ------------------ */
59
60
61 /*
62 * cfg_ClientQueryStatus() -- Query status of static client configuration
63 * on host, i.e., status of required configuration files, etc.
64 * Upon successful completion *configStP is set to the client
65 * configuration status, with a value of zero (0) indicating that
66 * the configuration is valid.
67 *
68 * If client configuration is not valid then *cellNameP is set to NULL;
69 * otherwise, *cellNameP is an allocated buffer containing client cell.
70 *
71 * If client software (cache-manager) is not installed then *versionP is
72 * undefined; otherwise *versionP is 34 for 3.4, 35 for 3.5, etc.
73 *
74 * Note: Client configuration is checked even if the client software
75 * is not installed. This is useful for tools that require
76 * client configuration information but NOT the actual
77 * client (cache-manager); for example, the AFS Server Manager.
78 */
79 int ADMINAPI
80 cfg_ClientQueryStatus(const char *hostName, /* name of host */
81 short *isInstalledP, /* client software installed */
82 unsigned *versionP, /* client software version */
83 afs_status_p configStP, /* client config status */
84 char **cellNameP, /* client's cell */
85 afs_status_p st)
86 { /* completion status */
87 int rc = 1;
88 afs_status_t tst2, tst = 0;
89 afs_status_t clientSt = 0;
90 char *clientCellName = NULL;
91 short cmInstalled = 0;
92 unsigned cmVersion = 0;
93
94 /* validate parameters */
95
96 if (hostName == NULL || *hostName == '\0') {
97 tst = ADMCFGHOSTNAMENULL;
98 } else if (strlen(hostName) > (MAXHOSTCHARS - 1)) {
99 tst = ADMCFGHOSTNAMETOOLONG;
100 } else if (isInstalledP == NULL) {
101 tst = ADMCFGINSTALLEDFLAGPNULL;
102 } else if (versionP == NULL) {
103 tst = ADMCFGVERSIONPNULL;
104 } else if (configStP == NULL) {
105 tst = ADMCFGCONFIGSTATUSPNULL;
106 } else if (cellNameP == NULL) {
107 tst = ADMCFGCELLNAMEPNULL;
108 }
109
110 /* remote configuration not yet supported; hostName must be local host */
111
112 if (tst == 0) {
113 short isLocal;
114
115 if (!cfgutil_HostNameIsLocal(hostName, &isLocal, &tst2)) {
116 tst = tst2;
117 } else if (!isLocal) {
118 tst = ADMCFGNOTSUPPORTED;
119 }
120 }
121
122 /* determine if client software (CM) is installed and if so what version */
123
124 #ifdef AFS_NT40_ENV
125 /* Windows - cache manager is a service */
126 if (tst == 0) {
127 DWORD svcState;
128
129 if (!cfgutil_WindowsServiceQuery
130 (AFSREG_CLT_SVC_NAME, &svcState, &tst2)) {
131 /* CM not installed, or insufficient privilege to check */
132 if (tst2 == ADMNOPRIV) {
133 tst = tst2;
134 } else {
135 cmInstalled = 0;
136 }
137 } else {
138 /* CM installed, get version */
139 unsigned major, minor, patch;
140
141 cmInstalled = 1;
142
143 if (afssw_GetClientVersion(&major, &minor, &patch)) {
144 /* failed to retrieve version information */
145 if (errno == EACCES) {
146 tst = ADMNOPRIV;
147 } else {
148 tst = ADMCFGCLIENTVERSIONNOTREAD;
149 }
150 } else {
151 cmVersion = (major * 10) + minor;
152 }
153 }
154 }
155 #else
156 if (tst == 0) {
157 /* function not yet implemented for Unix */
158 tst = ADMCFGNOTSUPPORTED;
159 }
160 #endif /* AFS_NT40_ENV */
161
162
163 /* check static client configuration; not necessary that client
164 * software (CM) be installed for this information to be valid and useable.
165 */
166
167 if (tst == 0) {
168 struct afsconf_dir *confdir;
169
170 if ((confdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH)) == NULL) {
171 /* the client configuration appears to be missing/invalid */
172 clientSt = ADMCFGCLIENTBASICINFOINVALID;
173 } else {
174 struct afsconf_entry *cellentry;
175
176 if (confdir->cellName == NULL || *confdir->cellName == '\0') {
177 /* no cell set for client */
178 clientSt = ADMCFGCLIENTNOTINCELL;
179 } else {
180 for (cellentry = confdir->entries; cellentry != NULL;
181 cellentry = cellentry->next) {
182 if (!strcasecmp
183 (confdir->cellName, cellentry->cellInfo.name)) {
184 break;
185 }
186 }
187
188 if (cellentry == NULL) {
189 clientSt = ADMCFGCLIENTCELLNOTINDB;
190 } else if (cellentry->cellInfo.numServers <= 0) {
191 clientSt = ADMCFGCLIENTCELLHASNODBENTRIES;
192 }
193 }
194
195 if (tst == 0 && clientSt == 0) {
196 /* everything looks good; malloc cell name buffer to return */
197 clientCellName = strdup(cellentry->cellInfo.name);
198 if (clientCellName == NULL)
199 tst = ADMNOMEM;
200 }
201
202 (void)afsconf_Close(confdir);
203 }
204 }
205
206 /* return result of query */
207
208 if (tst == 0) {
209 /* return client status and cell name */
210 *isInstalledP = cmInstalled;
211 *versionP = cmVersion;
212 *configStP = clientSt;
213
214 if (clientSt == 0) {
215 *cellNameP = clientCellName;
216 } else {
217 *cellNameP = NULL;
218 }
219 } else {
220 /* indicate failure */
221 rc = 0;
222
223 /* free cell name if allocated before failure */
224 if (clientCellName != NULL) {
225 free(clientCellName);
226 }
227 }
228 if (st != NULL) {
229 *st = tst;
230 }
231 return rc;
232 }
233
234
235 /*
236 * cfg_ClientSetCell() -- Define default client cell for host.
237 *
238 * The cellDbHosts argument is a multistring containing the names of
239 * the existing database servers already configured in the cell; this
240 * multistring list can be obtained via cfg_CellServDbEnumerate().
241 * If configuring the first server in a new cell then the cellDbHosts
242 * list contains only the name of that host.
243 *
244 * Warning: client (cache-manager) should be stopped prior to setting cell.
245 */
246 int ADMINAPI
247 cfg_ClientSetCell(void *hostHandle, /* host config handle */
248 const char *cellName, /* cell name */
249 const char *cellDbHosts, /* cell database hosts */
250 afs_status_p st)
251 { /* completion status */
252 int rc = 1;
253 afs_status_t tst2, tst = 0;
254 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
255
256 /* validate parameters */
257
258 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
259 tst = tst2;
260 } else if (cellName == NULL || *cellName == '\0') {
261 tst = ADMCFGCELLNAMENULL;
262 } else if (strlen(cellName) > (MAXCELLCHARS - 1)) {
263 tst = ADMCFGCELLNAMETOOLONG;
264 } else if (!cfgutil_HostHandleCellNameCompatible(cfg_host, cellName)) {
265 tst = ADMCFGCELLNAMECONFLICT;
266 } else if (cellDbHosts == NULL || *cellDbHosts == '\0') {
267 tst = ADMCFGCELLDBHOSTSNULL;
268 }
269
270 /* remote configuration not yet supported in this function */
271
272 if (tst == 0) {
273 if (!cfg_host->is_local) {
274 tst = ADMCFGNOTSUPPORTED;
275 }
276 }
277
278 /* define cell database hosts */
279
280 #ifdef AFS_NT40_ENV
281 if (tst == 0) {
282 CELLSERVDB clientDb;
283
284 if (!CSDB_ReadFile(&clientDb, AFSDIR_CLIENT_CELLSERVDB_FILEPATH)) {
285 tst = ADMCFGCLIENTCELLSERVDBNOTREAD;
286 } else {
287 CELLDBLINE *cellLinep = CSDB_FindCell(&clientDb, cellName);
288
289 if (cellLinep != NULL) {
290 /* cell entry exists; remove host entries */
291 if (!CSDB_RemoveCellServers(&clientDb, cellLinep)) {
292 /* should never happen */
293 tst = ADMCFGCLIENTCELLSERVDBEDITFAILED;
294 }
295 } else {
296 /* cell entry does not exist; add it */
297 cellLinep = CSDB_AddCell(&clientDb, cellName, NULL, NULL);
298
299 if (cellLinep == NULL) {
300 tst = ADMNOMEM;
301 }
302 }
303
304 if (tst == 0) {
305 /* add new host entries to cell */
306 const char *dbHost = cellDbHosts;
307 int dbHostCount = 0;
308
309 while (*dbHost != '\0' && tst == 0) {
310 size_t dbHostLen = strlen(dbHost);
311 const char *dbHostAddrStr;
312
313 if (dbHostLen > (MAXHOSTCHARS - 1)) {
314 tst = ADMCFGHOSTNAMETOOLONG;
315 } else if (dbHostCount >= MAXHOSTSPERCELL) {
316 tst = ADMCFGCELLDBHOSTCOUNTTOOLARGE;
317 } else
318 if (!cfgutil_HostNameGetAddressString
319 (dbHost, &dbHostAddrStr, &tst2)) {
320 tst = tst2;
321 } else
322 if (CSDB_AddCellServer
323 (&clientDb, cellLinep, dbHostAddrStr,
324 dbHost) == NULL) {
325 tst = ADMNOMEM;
326 } else {
327 dbHostCount++;
328 dbHost += dbHostLen + 1;
329 }
330 }
331
332 if (tst == 0) {
333 /* edit successful; write CellServDB */
334 if (!CSDB_WriteFile(&clientDb)) {
335 tst = ADMCFGCLIENTCELLSERVDBNOTWRITTEN;
336 }
337 }
338 }
339
340 CSDB_FreeFile(&clientDb);
341 }
342 }
343 #else
344 if (tst == 0) {
345 /* function not yet implemented for Unix */
346 tst = ADMCFGNOTSUPPORTED;
347 }
348 #endif /* AFS_NT40_ENV */
349
350
351 /* define default client cell */
352
353 #ifdef AFS_NT40_ENV
354 if (tst == 0) {
355 if (afssw_SetClientCellName(cellName)) {
356 /* failed to set cell name in registry (ThisCell equivalent) */
357 if (errno == EACCES) {
358 tst = ADMNOPRIV;
359 } else {
360 tst = ADMCFGCLIENTTHISCELLNOTWRITTEN;
361 }
362 }
363 }
364 #else
365 if (tst == 0) {
366 /* function not yet implemented for Unix */
367 tst = ADMCFGNOTSUPPORTED;
368 }
369 #endif /* AFS_NT40_ENV */
370
371
372 /* help any underlying packages adjust to cell change */
373
374 if (tst == 0) {
375 int rc;
376
377 if ((rc = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH)) != 0) {
378 tst = rc;
379 }
380 }
381
382 if (tst != 0) {
383 rc = 0;
384 }
385 if (st != NULL) {
386 *st = tst;
387 }
388 return rc;
389 }
390
391
392 /*
393 * cfg_ClientCellServDbAdd() -- Add entry to client CellServDB on host.
394 */
395 int ADMINAPI
396 cfg_ClientCellServDbAdd(void *hostHandle, /* host config handle */
397 const char *cellName, /* cell name */
398 const char *dbentry, /* cell database entry */
399 afs_status_p st)
400 { /* completion status */
401 return ClientCellServDbUpdate(CSDB_OP_ADD, hostHandle, cellName, dbentry,
402 st);
403 }
404
405
406 /*
407 * cfg_ClientCellServDbRemove() -- Remove entry from client CellServDB
408 * on host.
409 */
410 int ADMINAPI
411 cfg_ClientCellServDbRemove(void *hostHandle, /* host config handle */
412 const char *cellName, /* cell name */
413 const char *dbentry, /* cell database entry */
414 afs_status_p st)
415 { /* completion status */
416 return ClientCellServDbUpdate(CSDB_OP_REM, hostHandle, cellName, dbentry,
417 st);
418 }
419
420
421 /*
422 * cfg_ClientStop() -- Stop the client (cache manager) on host.
423 *
424 * Timeout is the maximum time (in seconds) to wait for client to stop.
425 */
426 int ADMINAPI
427 cfg_ClientStop(void *hostHandle, /* host config handle */
428 unsigned int timeout, /* timeout in seconds */
429 afs_status_p st)
430 { /* completion status */
431 int rc = 1;
432 afs_status_t tst2, tst = 0;
433 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
434
435 /* validate parameters */
436
437 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
438 tst = tst2;
439 }
440
441 /* remote configuration not yet supported in this function */
442
443 if (tst == 0) {
444 if (!cfg_host->is_local) {
445 tst = ADMCFGNOTSUPPORTED;
446 }
447 }
448
449 /* stop client */
450
451 if (tst == 0) {
452 if (!CacheManagerStop(timeout, &tst2)) {
453 tst = tst2;
454 }
455 }
456
457 if (tst != 0) {
458 /* indicate failure */
459 rc = 0;
460 }
461 if (st != NULL) {
462 *st = tst;
463 }
464 return rc;
465 }
466
467
468 /*
469 * cfg_ClientStart() -- Start the client (cache manager) on host.
470 *
471 * Timeout is the maximum time (in seconds) to wait for client to start.
472 */
473 int ADMINAPI
474 cfg_ClientStart(void *hostHandle, /* host config handle */
475 unsigned int timeout, /* timeout in seconds */
476 afs_status_p st)
477 { /* completion status */
478 int rc = 1;
479 afs_status_t tst2, tst = 0;
480 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
481
482 /* validate parameters */
483
484 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
485 tst = tst2;
486 }
487
488 /* remote configuration not yet supported in this function */
489
490 if (tst == 0) {
491 if (!cfg_host->is_local) {
492 tst = ADMCFGNOTSUPPORTED;
493 }
494 }
495
496 /* start client */
497
498 if (tst == 0) {
499 if (!CacheManagerStart(timeout, &tst2)) {
500 tst = tst2;
501 }
502 }
503
504 if (tst != 0) {
505 /* indicate failure */
506 rc = 0;
507 }
508 if (st != NULL) {
509 *st = tst;
510 }
511 return rc;
512 }
513
514
515
516 /* ---------------- Local functions ------------------ */
517
518
519 /*
520 * ClientCellServDbUpdate() -- add or remove a client CellServDB entry.
521 *
522 * Common function implementing cfg_ClientCellServDb{Add/Remove}().
523 */
524 static int
525 ClientCellServDbUpdate(int updateOp, void *hostHandle, const char *cellName,
526 const char *dbentry, afs_status_p st)
527 {
528 int rc = 1;
529 afs_status_t tst2, tst = 0;
530 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
531 char dbentryFull[MAXHOSTCHARS];
532
533 /* validate parameters and resolve dbentry to fully qualified name */
534
535 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
536 tst = tst2;
537 } else if (cellName == NULL || *cellName == '\0') {
538 tst = ADMCFGCELLNAMENULL;
539 } else if (strlen(cellName) > (MAXCELLCHARS - 1)) {
540 tst = ADMCFGCELLNAMETOOLONG;
541 } else if (dbentry == NULL || *dbentry == '\0') {
542 tst = ADMCFGHOSTNAMENULL;
543 } else if (strlen(dbentry) > (MAXHOSTCHARS - 1)) {
544 tst = ADMCFGHOSTNAMETOOLONG;
545 } else if (!cfgutil_HostNameGetFull(dbentry, dbentryFull, &tst2)) {
546 tst = tst2;
547 }
548
549 /* remote configuration not yet supported in this function */
550
551 if (tst == 0) {
552 if (!cfg_host->is_local) {
553 tst = ADMCFGNOTSUPPORTED;
554 }
555 }
556
557 /* modify local client CellServDB entry for specified cell */
558
559 #ifdef AFS_NT40_ENV
560 if (tst == 0) {
561 CELLSERVDB clientDb;
562
563 if (!CSDB_ReadFile(&clientDb, AFSDIR_CLIENT_CELLSERVDB_FILEPATH)) {
564 tst = ADMCFGCLIENTCELLSERVDBNOTREAD;
565 } else {
566 CELLDBLINE *cellLinep = CSDB_FindCell(&clientDb, cellName);
567 CELLDBLINE *serverLinep = NULL;
568 int serverLineCount = 0;
569
570 if (cellLinep != NULL) {
571 /* found cellName, now find server to add/remove */
572 CELLDBLINE *workingLinep;
573
574 for (workingLinep = cellLinep->pNext; workingLinep != NULL;
575 workingLinep = workingLinep->pNext) {
576 CELLDBLINEINFO lineInfo;
577
578 if (!CSDB_CrackLine(&lineInfo, workingLinep->szLine)) {
579 /* not a server (or cell) line; perhaps a comment */
580 continue;
581 } else if (lineInfo.szCell[0] != '\0') {
582 /* hit a new cell line */
583 break;
584 } else {
585 /* found a server line; check if is host of interest */
586 short isValid;
587 int dbentryAddr = ntohl(lineInfo.ipServer);
588
589 serverLineCount++;
590
591 if (!cfgutil_HostAddressIsValid
592 (dbentryFull, dbentryAddr, &isValid, &tst2)) {
593 tst = tst2;
594 break;
595 } else if (isValid) {
596 /* found server of interest */
597 serverLinep = workingLinep;
598 break;
599 }
600 }
601 }
602 }
603
604 if (tst == 0) {
605 if (updateOp == CSDB_OP_ADD && serverLinep == NULL) {
606 if (cellLinep == NULL) {
607 cellLinep =
608 CSDB_AddCell(&clientDb, cellName, NULL, NULL);
609 }
610
611 if (cellLinep == NULL) {
612 tst = ADMNOMEM;
613 } else if (serverLineCount >= MAXHOSTSPERCELL) {
614 tst = ADMCFGCLIENTCELLSERVDBNOSPACE;
615 } else {
616 const char *dbentryAddrStr;
617
618 if (!cfgutil_HostNameGetAddressString
619 (dbentryFull, &dbentryAddrStr, &tst2)) {
620 tst = tst2;
621 } else {
622 serverLinep =
623 CSDB_AddCellServer(&clientDb, cellLinep,
624 dbentryAddrStr,
625 dbentryFull);
626 if (serverLinep == NULL) {
627 tst = ADMNOMEM;
628 }
629 }
630 }
631 } else if (updateOp == CSDB_OP_REM && serverLinep != NULL) {
632 (void)CSDB_RemoveLine(&clientDb, serverLinep);
633 }
634
635 if (tst == 0) {
636 if (!CSDB_WriteFile(&clientDb)) {
637 tst = ADMCFGCLIENTCELLSERVDBNOTWRITTEN;
638 }
639 }
640 }
641
642 CSDB_FreeFile(&clientDb);
643 }
644 }
645 #else
646 if (tst == 0) {
647 /* function not yet implemented for Unix */
648 tst = ADMCFGNOTSUPPORTED;
649 }
650 #endif /* AFS_NT40_ENV */
651
652 if (tst != 0) {
653 /* indicate failure */
654 rc = 0;
655 }
656 if (st != NULL) {
657 *st = tst;
658 }
659 return rc;
660 }
661
662
663 /*
664 * CacheManagerStart() -- Start the local AFS cache manager.
665 *
666 * Timeout is the maximum time (in seconds) to wait for the CM to start.
667 *
668 * RETURN CODES: 1 success, 0 failure (st indicates why)
669 */
670 static int
671 CacheManagerStart(unsigned timeout, afs_status_p st)
672 {
673 int rc = 1;
674 #ifdef AFS_NT40_ENV
675 afs_status_t tst2;
676 #endif
677 afs_status_t tst = 0;
678
679 #ifdef AFS_NT40_ENV
680 /* Windows - cache manager is a service */
681 short wasRunning;
682
683 if (!cfgutil_WindowsServiceStart
684 (AFSREG_CLT_SVC_NAME, 0, NULL, timeout, &wasRunning, &tst2)) {
685 tst = tst2;
686 }
687 #else
688 /* function not yet implemented for Unix */
689 tst = ADMCFGNOTSUPPORTED;
690 #endif /* AFS_NT40_ENV */
691
692 if (tst != 0) {
693 /* indicate failure */
694 rc = 0;
695 }
696 if (st != NULL) {
697 *st = tst;
698 }
699 return rc;
700 }
701
702
703 /*
704 * CacheManagerStop() -- Stop the local AFS cache manager.
705 *
706 * Timeout is the maximum time (in seconds) to wait for the CM to stop.
707 *
708 * RETURN CODES: 1 success, 0 failure (st indicates why)
709 */
710 static int
711 CacheManagerStop(unsigned timeout, afs_status_p st)
712 {
713 int rc = 1;
714 #ifdef AFS_NT40_ENV
715 afs_status_t tst2;
716 #endif
717 afs_status_t tst = 0;
718
719 #ifdef AFS_NT40_ENV
720 /* Windows - cache manager is a service */
721 short wasStopped;
722
723 if (!cfgutil_WindowsServiceStop
724 (AFSREG_CLT_SVC_NAME, timeout, &wasStopped, &tst2)) {
725 tst = tst2;
726 }
727 #else
728 /* function not yet implemented for Unix */
729 tst = ADMCFGNOTSUPPORTED;
730 #endif /* AFS_NT40_ENV */
731
732 if (tst != 0) {
733 /* indicate failure */
734 rc = 0;
735 }
736 if (st != NULL) {
737 *st = tst;
738 }
739 return rc;
740 }