libadmin: Tidy header includes
[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 =
198                     (char *)malloc(strlen(cellentry->cellInfo.name) + 1);
199                 if (clientCellName == NULL) {
200                     tst = ADMNOMEM;
201                 } else {
202                     strcpy(clientCellName, cellentry->cellInfo.name);
203                 }
204             }
205
206             (void)afsconf_Close(confdir);
207         }
208     }
209
210     /* return result of query */
211
212     if (tst == 0) {
213         /* return client status and cell name */
214         *isInstalledP = cmInstalled;
215         *versionP = cmVersion;
216         *configStP = clientSt;
217
218         if (clientSt == 0) {
219             *cellNameP = clientCellName;
220         } else {
221             *cellNameP = NULL;
222         }
223     } else {
224         /* indicate failure */
225         rc = 0;
226
227         /* free cell name if allocated before failure */
228         if (clientCellName != NULL) {
229             free(clientCellName);
230         }
231     }
232     if (st != NULL) {
233         *st = tst;
234     }
235     return rc;
236 }
237
238
239 /*
240  * cfg_ClientSetCell() -- Define default client cell for host.
241  *
242  *     The cellDbHosts argument is a multistring containing the names of
243  *     the existing database servers already configured in the cell; this
244  *     multistring list can be obtained via cfg_CellServDbEnumerate().
245  *     If configuring the first server in a new cell then the cellDbHosts
246  *     list contains only the name of that host.
247  *
248  *     Warning: client (cache-manager) should be stopped prior to setting cell.
249  */
250 int ADMINAPI
251 cfg_ClientSetCell(void *hostHandle,     /* host config handle */
252                   const char *cellName, /* cell name */
253                   const char *cellDbHosts,      /* cell database hosts */
254                   afs_status_p st)
255 {                               /* completion status */
256     int rc = 1;
257     afs_status_t tst2, tst = 0;
258     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
259
260     /* validate parameters */
261
262     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
263         tst = tst2;
264     } else if (cellName == NULL || *cellName == '\0') {
265         tst = ADMCFGCELLNAMENULL;
266     } else if (strlen(cellName) > (MAXCELLCHARS - 1)) {
267         tst = ADMCFGCELLNAMETOOLONG;
268     } else if (!cfgutil_HostHandleCellNameCompatible(cfg_host, cellName)) {
269         tst = ADMCFGCELLNAMECONFLICT;
270     } else if (cellDbHosts == NULL || *cellDbHosts == '\0') {
271         tst = ADMCFGCELLDBHOSTSNULL;
272     }
273
274     /* remote configuration not yet supported in this function */
275
276     if (tst == 0) {
277         if (!cfg_host->is_local) {
278             tst = ADMCFGNOTSUPPORTED;
279         }
280     }
281
282     /* define cell database hosts */
283
284 #ifdef AFS_NT40_ENV
285     if (tst == 0) {
286         CELLSERVDB clientDb;
287
288         if (!CSDB_ReadFile(&clientDb, AFSDIR_CLIENT_CELLSERVDB_FILEPATH)) {
289             tst = ADMCFGCLIENTCELLSERVDBNOTREAD;
290         } else {
291             CELLDBLINE *cellLinep = CSDB_FindCell(&clientDb, cellName);
292
293             if (cellLinep != NULL) {
294                 /* cell entry exists; remove host entries */
295                 if (!CSDB_RemoveCellServers(&clientDb, cellLinep)) {
296                     /* should never happen */
297                     tst = ADMCFGCLIENTCELLSERVDBEDITFAILED;
298                 }
299             } else {
300                 /* cell entry does not exist; add it */
301                 cellLinep = CSDB_AddCell(&clientDb, cellName, NULL, NULL);
302
303                 if (cellLinep == NULL) {
304                     tst = ADMNOMEM;
305                 }
306             }
307
308             if (tst == 0) {
309                 /* add new host entries to cell */
310                 const char *dbHost = cellDbHosts;
311                 int dbHostCount = 0;
312
313                 while (*dbHost != '\0' && tst == 0) {
314                     size_t dbHostLen = strlen(dbHost);
315                     const char *dbHostAddrStr;
316
317                     if (dbHostLen > (MAXHOSTCHARS - 1)) {
318                         tst = ADMCFGHOSTNAMETOOLONG;
319                     } else if (dbHostCount >= MAXHOSTSPERCELL) {
320                         tst = ADMCFGCELLDBHOSTCOUNTTOOLARGE;
321                     } else
322                         if (!cfgutil_HostNameGetAddressString
323                             (dbHost, &dbHostAddrStr, &tst2)) {
324                         tst = tst2;
325                     } else
326                         if (CSDB_AddCellServer
327                             (&clientDb, cellLinep, dbHostAddrStr,
328                              dbHost) == NULL) {
329                         tst = ADMNOMEM;
330                     } else {
331                         dbHostCount++;
332                         dbHost += dbHostLen + 1;
333                     }
334                 }
335
336                 if (tst == 0) {
337                     /* edit successful; write CellServDB */
338                     if (!CSDB_WriteFile(&clientDb)) {
339                         tst = ADMCFGCLIENTCELLSERVDBNOTWRITTEN;
340                     }
341                 }
342             }
343
344             CSDB_FreeFile(&clientDb);
345         }
346     }
347 #else
348     if (tst == 0) {
349         /* function not yet implemented for Unix */
350         tst = ADMCFGNOTSUPPORTED;
351     }
352 #endif /* AFS_NT40_ENV */
353
354
355     /* define default client cell */
356
357 #ifdef AFS_NT40_ENV
358     if (tst == 0) {
359         if (afssw_SetClientCellName(cellName)) {
360             /* failed to set cell name in registry (ThisCell equivalent) */
361             if (errno == EACCES) {
362                 tst = ADMNOPRIV;
363             } else {
364                 tst = ADMCFGCLIENTTHISCELLNOTWRITTEN;
365             }
366         }
367     }
368 #else
369     if (tst == 0) {
370         /* function not yet implemented for Unix */
371         tst = ADMCFGNOTSUPPORTED;
372     }
373 #endif /* AFS_NT40_ENV */
374
375
376     /* help any underlying packages adjust to cell change */
377
378     if (tst == 0) {
379         int rc;
380
381         if ((rc = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH)) != 0) {
382             tst = rc;
383         }
384     }
385
386     if (tst != 0) {
387         rc = 0;
388     }
389     if (st != NULL) {
390         *st = tst;
391     }
392     return rc;
393 }
394
395
396 /*
397  * cfg_ClientCellServDbAdd() -- Add entry to client CellServDB on host.
398  */
399 int ADMINAPI
400 cfg_ClientCellServDbAdd(void *hostHandle,       /* host config handle */
401                         const char *cellName,   /* cell name */
402                         const char *dbentry,    /* cell database entry */
403                         afs_status_p st)
404 {                               /* completion status */
405     return ClientCellServDbUpdate(CSDB_OP_ADD, hostHandle, cellName, dbentry,
406                                   st);
407 }
408
409
410 /*
411  * cfg_ClientCellServDbRemove() -- Remove entry from client CellServDB
412  *     on host.
413  */
414 int ADMINAPI
415 cfg_ClientCellServDbRemove(void *hostHandle,    /* host config handle */
416                            const char *cellName,        /* cell name */
417                            const char *dbentry, /* cell database entry */
418                            afs_status_p st)
419 {                               /* completion status */
420     return ClientCellServDbUpdate(CSDB_OP_REM, hostHandle, cellName, dbentry,
421                                   st);
422 }
423
424
425 /*
426  * cfg_ClientStop() -- Stop the client (cache manager) on host.
427  *
428  *     Timeout is the maximum time (in seconds) to wait for client to stop.
429  */
430 int ADMINAPI
431 cfg_ClientStop(void *hostHandle,        /* host config handle */
432                unsigned int timeout,    /* timeout in seconds */
433                afs_status_p st)
434 {                               /* completion status */
435     int rc = 1;
436     afs_status_t tst2, tst = 0;
437     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
438
439     /* validate parameters */
440
441     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
442         tst = tst2;
443     }
444
445     /* remote configuration not yet supported in this function */
446
447     if (tst == 0) {
448         if (!cfg_host->is_local) {
449             tst = ADMCFGNOTSUPPORTED;
450         }
451     }
452
453     /* stop client */
454
455     if (tst == 0) {
456         if (!CacheManagerStop(timeout, &tst2)) {
457             tst = tst2;
458         }
459     }
460
461     if (tst != 0) {
462         /* indicate failure */
463         rc = 0;
464     }
465     if (st != NULL) {
466         *st = tst;
467     }
468     return rc;
469 }
470
471
472 /*
473  * cfg_ClientStart() -- Start the client (cache manager) on host.
474  *
475  *     Timeout is the maximum time (in seconds) to wait for client to start.
476  */
477 int ADMINAPI
478 cfg_ClientStart(void *hostHandle,       /* host config handle */
479                 unsigned int timeout,   /* timeout in seconds */
480                 afs_status_p st)
481 {                               /* completion status */
482     int rc = 1;
483     afs_status_t tst2, tst = 0;
484     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
485
486     /* validate parameters */
487
488     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
489         tst = tst2;
490     }
491
492     /* remote configuration not yet supported in this function */
493
494     if (tst == 0) {
495         if (!cfg_host->is_local) {
496             tst = ADMCFGNOTSUPPORTED;
497         }
498     }
499
500     /* start client */
501
502     if (tst == 0) {
503         if (!CacheManagerStart(timeout, &tst2)) {
504             tst = tst2;
505         }
506     }
507
508     if (tst != 0) {
509         /* indicate failure */
510         rc = 0;
511     }
512     if (st != NULL) {
513         *st = tst;
514     }
515     return rc;
516 }
517
518
519
520 /* ---------------- Local functions ------------------ */
521
522
523 /*
524  * ClientCellServDbUpdate() -- add or remove a client CellServDB entry.
525  *
526  *     Common function implementing cfg_ClientCellServDb{Add/Remove}().
527  */
528 static int
529 ClientCellServDbUpdate(int updateOp, void *hostHandle, const char *cellName,
530                        const char *dbentry, afs_status_p st)
531 {
532     int rc = 1;
533     afs_status_t tst2, tst = 0;
534     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
535     char dbentryFull[MAXHOSTCHARS];
536
537     /* validate parameters and resolve dbentry to fully qualified name */
538
539     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
540         tst = tst2;
541     } else if (cellName == NULL || *cellName == '\0') {
542         tst = ADMCFGCELLNAMENULL;
543     } else if (strlen(cellName) > (MAXCELLCHARS - 1)) {
544         tst = ADMCFGCELLNAMETOOLONG;
545     } else if (dbentry == NULL || *dbentry == '\0') {
546         tst = ADMCFGHOSTNAMENULL;
547     } else if (strlen(dbentry) > (MAXHOSTCHARS - 1)) {
548         tst = ADMCFGHOSTNAMETOOLONG;
549     } else if (!cfgutil_HostNameGetFull(dbentry, dbentryFull, &tst2)) {
550         tst = tst2;
551     }
552
553     /* remote configuration not yet supported in this function */
554
555     if (tst == 0) {
556         if (!cfg_host->is_local) {
557             tst = ADMCFGNOTSUPPORTED;
558         }
559     }
560
561     /* modify local client CellServDB entry for specified cell */
562
563 #ifdef AFS_NT40_ENV
564     if (tst == 0) {
565         CELLSERVDB clientDb;
566
567         if (!CSDB_ReadFile(&clientDb, AFSDIR_CLIENT_CELLSERVDB_FILEPATH)) {
568             tst = ADMCFGCLIENTCELLSERVDBNOTREAD;
569         } else {
570             CELLDBLINE *cellLinep = CSDB_FindCell(&clientDb, cellName);
571             CELLDBLINE *serverLinep = NULL;
572             int serverLineCount = 0;
573
574             if (cellLinep != NULL) {
575                 /* found cellName, now find server to add/remove */
576                 CELLDBLINE *workingLinep;
577
578                 for (workingLinep = cellLinep->pNext; workingLinep != NULL;
579                      workingLinep = workingLinep->pNext) {
580                     CELLDBLINEINFO lineInfo;
581
582                     if (!CSDB_CrackLine(&lineInfo, workingLinep->szLine)) {
583                         /* not a server (or cell) line; perhaps a comment */
584                         continue;
585                     } else if (lineInfo.szCell[0] != '\0') {
586                         /* hit a new cell line */
587                         break;
588                     } else {
589                         /* found a server line; check if is host of interest */
590                         short isValid;
591                         int dbentryAddr = ntohl(lineInfo.ipServer);
592
593                         serverLineCount++;
594
595                         if (!cfgutil_HostAddressIsValid
596                             (dbentryFull, dbentryAddr, &isValid, &tst2)) {
597                             tst = tst2;
598                             break;
599                         } else if (isValid) {
600                             /* found server of interest */
601                             serverLinep = workingLinep;
602                             break;
603                         }
604                     }
605                 }
606             }
607
608             if (tst == 0) {
609                 if (updateOp == CSDB_OP_ADD && serverLinep == NULL) {
610                     if (cellLinep == NULL) {
611                         cellLinep =
612                             CSDB_AddCell(&clientDb, cellName, NULL, NULL);
613                     }
614
615                     if (cellLinep == NULL) {
616                         tst = ADMNOMEM;
617                     } else if (serverLineCount >= MAXHOSTSPERCELL) {
618                         tst = ADMCFGCLIENTCELLSERVDBNOSPACE;
619                     } else {
620                         const char *dbentryAddrStr;
621
622                         if (!cfgutil_HostNameGetAddressString
623                             (dbentryFull, &dbentryAddrStr, &tst2)) {
624                             tst = tst2;
625                         } else {
626                             serverLinep =
627                                 CSDB_AddCellServer(&clientDb, cellLinep,
628                                                    dbentryAddrStr,
629                                                    dbentryFull);
630                             if (serverLinep == NULL) {
631                                 tst = ADMNOMEM;
632                             }
633                         }
634                     }
635                 } else if (updateOp == CSDB_OP_REM && serverLinep != NULL) {
636                     (void)CSDB_RemoveLine(&clientDb, serverLinep);
637                 }
638
639                 if (tst == 0) {
640                     if (!CSDB_WriteFile(&clientDb)) {
641                         tst = ADMCFGCLIENTCELLSERVDBNOTWRITTEN;
642                     }
643                 }
644             }
645
646             CSDB_FreeFile(&clientDb);
647         }
648     }
649 #else
650     if (tst == 0) {
651         /* function not yet implemented for Unix */
652         tst = ADMCFGNOTSUPPORTED;
653     }
654 #endif /* AFS_NT40_ENV */
655
656     if (tst != 0) {
657         /* indicate failure */
658         rc = 0;
659     }
660     if (st != NULL) {
661         *st = tst;
662     }
663     return rc;
664 }
665
666
667 /*
668  * CacheManagerStart() -- Start the local AFS cache manager.
669  *
670  *     Timeout is the maximum time (in seconds) to wait for the CM to start.
671  *
672  * RETURN CODES: 1 success, 0 failure (st indicates why)
673  */
674 static int
675 CacheManagerStart(unsigned timeout, afs_status_p st)
676 {
677     int rc = 1;
678 #ifdef AFS_NT40_ENV
679     afs_status_t tst2;
680 #endif
681     afs_status_t tst = 0;
682
683 #ifdef AFS_NT40_ENV
684     /* Windows - cache manager is a service */
685     short wasRunning;
686
687     if (!cfgutil_WindowsServiceStart
688         (AFSREG_CLT_SVC_NAME, 0, NULL, timeout, &wasRunning, &tst2)) {
689         tst = tst2;
690     }
691 #else
692     /* function not yet implemented for Unix */
693     tst = ADMCFGNOTSUPPORTED;
694 #endif /* AFS_NT40_ENV */
695
696     if (tst != 0) {
697         /* indicate failure */
698         rc = 0;
699     }
700     if (st != NULL) {
701         *st = tst;
702     }
703     return rc;
704 }
705
706
707 /*
708  * CacheManagerStop() -- Stop the local AFS cache manager.
709  *
710  *     Timeout is the maximum time (in seconds) to wait for the CM to stop.
711  *
712  * RETURN CODES: 1 success, 0 failure (st indicates why)
713  */
714 static int
715 CacheManagerStop(unsigned timeout, afs_status_p st)
716 {
717     int rc = 1;
718 #ifdef AFS_NT40_ENV
719     afs_status_t tst2;
720 #endif
721     afs_status_t tst = 0;
722
723 #ifdef AFS_NT40_ENV
724     /* Windows - cache manager is a service */
725     short wasStopped;
726
727     if (!cfgutil_WindowsServiceStop
728         (AFSREG_CLT_SVC_NAME, timeout, &wasStopped, &tst2)) {
729         tst = tst2;
730     }
731 #else
732     /* function not yet implemented for Unix */
733     tst = ADMCFGNOTSUPPORTED;
734 #endif /* AFS_NT40_ENV */
735
736     if (tst != 0) {
737         /* indicate failure */
738         rc = 0;
739     }
740     if (st != NULL) {
741         *st = tst;
742     }
743     return rc;
744 }