5c40e236622cfc37e9f92009823b9a95d562d0fd
[openafs.git] / src / libadmin / cfg / cfghost.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_Host*()         - manipulate static server configuration information.
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #include <roken.h>
19
20 #include <pthread.h>
21
22 #ifdef AFS_NT40_ENV
23 #include <WINNT/vptab.h>
24 #include <WINNT/afsreg.h>
25 #include <direct.h>
26 #endif /* AFS_NT40_ENV */
27
28 #include <rx/rx.h>
29 #include <rx/rxstat.h>
30
31 #include <afs/afs_Admin.h>
32 #include <afs/afs_AdminErrors.h>
33 #include <afs/afs_utilAdmin.h>
34 #include <afs/afs_bosAdmin.h>
35 #include <afs/afs_clientAdmin.h>
36 #include <afs/afs_kasAdmin.h>
37 #include <afs/afs_ptsAdmin.h>
38
39 #include <afs/kautils.h>
40 #include <afs/bnode.h>
41 #include <afs/prerror.h>
42 #include <afs/keys.h>
43 #include <afs/dirpath.h>
44 #include <afs/cellconfig.h>
45
46 #include "cfginternal.h"
47 #include "afs_cfgAdmin.h"
48 #include "../adminutil/afs_AdminInternal.h"
49
50
51
52 /* Local declarations and definitions */
53
54 static int
55   KasKeyIsZero(kas_encryptionKey_t * kasKey);
56
57 static int
58   KasKeyEmbeddedInString(const char *keyString, kas_encryptionKey_t * kasKey);
59
60
61
62
63 /* ---------------- Exported Server Host functions ------------------ */
64
65
66 /*
67  * cfg_HostQueryStatus() -- Query status of static server configuration
68  *     on host, i.e., status of required configuration files, etc.
69  *     Upon successful completion *configStP is set to the server
70  *     configuration status, with a value of zero (0) indicating that
71  *     the configuration is valid.
72  *
73  *     If server configuration is not valid then *cellNameP is set to NULL;
74  *     otherwise, *cellNameP is an allocated buffer containing server cell.
75  *
76  *     Warning: in determining if server configuration is valid, no check
77  *     is made for consistency with other servers in cell; also, the
78  *     internal consistency of configuration files may not be verified.
79  */
80 int ADMINAPI
81 cfg_HostQueryStatus(const char *hostName,       /* name of host */
82                     afs_status_p configStP,     /* server config status */
83                     char **cellNameP,   /* server's cell */
84                     afs_status_p st)
85 {                               /* completion status */
86     int rc = 1;
87     struct afsconf_keys keys;
88     afs_status_t tst2, tst = 0;
89     afs_status_t serverSt = 0;
90     char *serverCellName = NULL;
91
92     /* validate parameters */
93
94     if (hostName == NULL || *hostName == '\0') {
95         tst = ADMCFGHOSTNAMENULL;
96     } else if (strlen(hostName) > (MAXHOSTCHARS - 1)) {
97         tst = ADMCFGHOSTNAMETOOLONG;
98     } else if (configStP == NULL) {
99         tst = ADMCFGCONFIGSTATUSPNULL;
100     } else if (cellNameP == NULL) {
101         tst = ADMCFGCELLNAMEPNULL;
102     }
103
104     /* remote configuration not yet supported; hostName must be local host */
105
106     if (tst == 0) {
107         short isLocal;
108
109         if (!cfgutil_HostNameIsLocal(hostName, &isLocal, &tst2)) {
110             tst = tst2;
111         } else if (!isLocal) {
112             tst = ADMCFGNOTSUPPORTED;
113         }
114     }
115
116     /* check for existence and readability of required server config files */
117
118     if (tst == 0) {
119         int i;
120         const char *cfgfile[4];
121
122         cfgfile[0] = AFSDIR_SERVER_THISCELL_FILEPATH;
123         cfgfile[1] = AFSDIR_SERVER_CELLSERVDB_FILEPATH;
124         cfgfile[2] = AFSDIR_SERVER_KEY_FILEPATH;
125         cfgfile[3] = AFSDIR_SERVER_ULIST_FILEPATH;
126
127         for (i = 0; i < 4; i++) {
128             int fd;
129             if ((fd = open(cfgfile[i], O_RDONLY)) < 0) {
130                 break;
131             }
132             (void)close(fd);
133         }
134
135         if (i < 4) {
136             if (errno == EACCES) {
137                 tst = ADMNOPRIV;
138             } else {
139                 serverSt = ADMCFGSERVERBASICINFOINVALID;
140             }
141         }
142     }
143
144     /* verify the required server config files to the degree possible */
145
146     if (tst == 0 && serverSt == 0) {
147         struct afsconf_dir *confdir;
148
149         if ((confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH)) == NULL) {
150             /* one or more config files appears to be invalid */
151             serverSt = ADMCFGSERVERBASICINFOINVALID;
152         } else {
153             struct afsconf_entry *cellentry = NULL;
154
155             if (confdir->cellName == NULL || *confdir->cellName == '\0') {
156                 /* no cell set for server */
157                 serverSt = ADMCFGSERVERNOTINCELL;
158             } else if ((afsconf_GetKeys(confdir, &keys) != 0)
159                        || (keys.nkeys == 0)) {
160                 /* no server keys */
161                 serverSt = ADMCFGSERVERNOKEYS;
162             } else {
163                 for (cellentry = confdir->entries; cellentry != NULL;
164                      cellentry = cellentry->next) {
165                     if (!strcasecmp
166                         (confdir->cellName, cellentry->cellInfo.name)) {
167                         break;
168                     }
169                 }
170
171                 if (cellentry == NULL) {
172                     serverSt = ADMCFGSERVERCELLNOTINDB;
173                 } else if (cellentry->cellInfo.numServers <= 0) {
174                     serverSt = ADMCFGSERVERCELLHASNODBENTRIES;
175                 }
176             }
177
178             if (tst == 0 && serverSt == 0) {
179                 /* everything looks good; malloc cell name buffer to return */
180                 serverCellName = strdup(cellentry->cellInfo.name);
181                 if (serverCellName == NULL)
182                     tst = ADMNOMEM;
183             }
184
185             (void)afsconf_Close(confdir);
186         }
187     }
188
189     if (tst == 0) {
190         /* return server status and cell name */
191         *configStP = serverSt;
192
193         if (serverSt == 0) {
194             *cellNameP = serverCellName;
195         } else {
196             *cellNameP = NULL;
197         }
198     } else {
199         /* indicate failure */
200         rc = 0;
201
202         /* free cell name if allocated before failure */
203         if (serverCellName != NULL) {
204             free(serverCellName);
205         }
206     }
207     if (st != NULL) {
208         *st = tst;
209     }
210     return rc;
211 }
212
213
214 /*
215  * cfg_HostOpen() -- Obtain host configuration handle.
216  */
217 int ADMINAPI
218 cfg_HostOpen(void *cellHandle,  /* cell handle */
219              const char *hostName,      /* name of host to configure */
220              void **hostHandleP,        /* host config handle */
221              afs_status_p st)
222 {                               /* completion status */
223     int rc = 1;
224     afs_status_t tst2, tst = 0;
225     cfg_host_p cfg_host;
226     char fullHostName[MAXHOSTCHARS];
227
228     /* validate parameters and resolve host name to fully qualified name */
229
230     if (!CellHandleIsValid(cellHandle, &tst2)) {
231         tst = tst2;
232     } else if (hostName == NULL || *hostName == '\0') {
233         tst = ADMCFGHOSTNAMENULL;
234     } else if (strlen(hostName) > (MAXHOSTCHARS - 1)) {
235         tst = ADMCFGHOSTNAMETOOLONG;
236     } else if (hostHandleP == NULL) {
237         tst = ADMCFGHOSTHANDLEPNULL;
238     } else if (!cfgutil_HostNameGetFull(hostName, fullHostName, &tst2)) {
239         tst = tst2;
240     }
241
242     /* remote configuration not yet supported; hostName must be local host */
243
244     if (tst == 0) {
245         short isLocal;
246
247         if (!cfgutil_HostNameIsLocal(hostName, &isLocal, &tst2)) {
248             tst = tst2;
249         } else if (!isLocal) {
250             tst = ADMCFGNOTSUPPORTED;
251         }
252     }
253
254     /* allocate a host configuration handle */
255
256     if (tst == 0) {
257         char *localHostName;
258
259         if ((cfg_host = (cfg_host_p) malloc(sizeof(cfg_host_t))) == NULL) {
260             tst = ADMNOMEM;
261         } else if ((localHostName = strdup(fullHostName)) == NULL) {
262             free(cfg_host);
263             tst = ADMNOMEM;
264         } else {
265             /* initialize handle */
266             cfg_host->begin_magic = BEGIN_MAGIC;
267             cfg_host->is_valid = 1;
268             cfg_host->hostName = localHostName;
269             cfg_host->is_local = 1;     /* not yet supporting remote config */
270             cfg_host->cellHandle = cellHandle;
271             cfg_host->bosHandle = NULL;
272             cfg_host->end_magic = END_MAGIC;
273
274             if (!afsclient_CellNameGet
275                 (cfg_host->cellHandle, &cfg_host->cellName, &tst2)) {
276                 tst = tst2;
277             } else if (pthread_mutex_init(&cfg_host->mutex, NULL)) {
278                 tst = ADMMUTEXINIT;
279             }
280
281             if (tst != 0) {
282                 /* cell name lookup or mutex initialization failed */
283                 free(localHostName);
284                 free(cfg_host);
285             }
286         }
287     }
288
289     if (tst == 0) {
290         /* success; return host config handle to user */
291         *hostHandleP = cfg_host;
292     } else {
293         /* indicate failure */
294         rc = 0;
295     }
296     if (st != NULL) {
297         *st = tst;
298     }
299     return rc;
300 }
301
302
303 /*
304  * cfg_HostClose() -- Release host configuration handle.
305  */
306 int ADMINAPI
307 cfg_HostClose(void *hostHandle, /* host config handle */
308               afs_status_p st)
309 {                               /* completion status */
310     int rc = 1;
311     afs_status_t tst2, tst = 0;
312     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
313
314     /* validate parameters */
315
316     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
317         tst = tst2;
318     }
319
320     /* free handle; can assume no other thread using this handle */
321
322     if (tst == 0) {
323         /* mark cfg handle invalid in case use after free (bug catcher) */
324         cfg_host->is_valid = 0;
325
326         if (cfg_host->bosHandle != NULL) {
327             if (!bos_ServerClose(cfg_host->bosHandle, &tst2)) {
328                 tst = tst2;
329             }
330         }
331         free(cfg_host->hostName);
332         (void)pthread_mutex_destroy(&cfg_host->mutex);
333         free(cfg_host);
334     }
335
336     if (tst != 0) {
337         rc = 0;
338     }
339     if (st != NULL) {
340         *st = tst;
341     }
342     return rc;
343 }
344
345
346 /*
347  * cfg_HostSetCell() -- Define server cell membership for host.
348  *
349  *     The cellDbHosts argument is a multistring containing the names of
350  *     the existing database servers already configured in the cell; this
351  *     multistring list can be obtained via cfg_CellServDbEnumerate().
352  *     If configuring the first server in a new cell then the cellDbHosts
353  *     list contains only the name of that host.
354  *
355  *     Note: The names in cellDbHosts MUST exactly match those in the
356  *           cell-wide server CellServDB; using cfg_CellServDbEnumerate()
357  *           is highly recommended.
358  */
359 int ADMINAPI
360 cfg_HostSetCell(void *hostHandle,       /* host config handle */
361                 const char *cellName,   /* cell name */
362                 const char *cellDbHosts,        /* cell database hosts */
363                 afs_status_p st)
364 {                               /* completion status */
365     int rc = 1;
366     afs_status_t tst2, tst = 0;
367     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
368
369     /* validate parameters */
370
371     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
372         tst = tst2;
373     } else if (cellName == NULL || *cellName == '\0') {
374         tst = ADMCFGCELLNAMENULL;
375     } else if (strlen(cellName) > (MAXCELLCHARS - 1)) {
376         tst = ADMCFGCELLNAMETOOLONG;
377     } else if (!cfgutil_HostHandleCellNameCompatible(cfg_host, cellName)) {
378         tst = ADMCFGCELLNAMECONFLICT;
379     } else if (cellDbHosts == NULL || *cellDbHosts == '\0') {
380         tst = ADMCFGCELLDBHOSTSNULL;
381     }
382
383     /* remote configuration not yet supported in this function */
384
385     if (tst == 0) {
386         if (!cfg_host->is_local) {
387             tst = ADMCFGNOTSUPPORTED;
388         }
389     }
390
391     /* define server cell and cell database hosts */
392
393     if (tst == 0) {
394         const char *dbHost = cellDbHosts;
395         struct afsconf_cell hostCell;
396         memset(&hostCell, 0, sizeof(hostCell));
397
398         strcpy(hostCell.name, cellName);
399         hostCell.numServers = 0;
400
401         while (*dbHost != '\0' && tst == 0) {
402             /* fill in each database host */
403             size_t dbHostLen = strlen(dbHost);
404
405             if (dbHostLen > (MAXHOSTCHARS - 1)) {
406                 tst = ADMCFGHOSTNAMETOOLONG;
407             } else if (hostCell.numServers >= MAXHOSTSPERCELL) {
408                 tst = ADMCFGCELLDBHOSTCOUNTTOOLARGE;
409             } else {
410                 strcpy(hostCell.hostName[hostCell.numServers++], dbHost);
411                 dbHost += dbHostLen + 1;
412             }
413         }
414
415         if (tst == 0) {
416             /* create server ThisCell/CellServDB dir if it does not exist */
417 #ifdef AFS_NT40_ENV
418             (void)mkdir(AFSDIR_USR_DIRPATH);
419             (void)mkdir(AFSDIR_SERVER_AFS_DIRPATH);
420             (void)mkdir(AFSDIR_SERVER_ETC_DIRPATH);
421 #else
422             (void)mkdir(AFSDIR_USR_DIRPATH, 0755);
423             (void)mkdir(AFSDIR_SERVER_AFS_DIRPATH, 0755);
424             (void)mkdir(AFSDIR_SERVER_ETC_DIRPATH, 0755);
425 #endif
426             if (afsconf_SetCellInfo
427                 (NULL, AFSDIR_SERVER_ETC_DIRPATH, &hostCell)) {
428                 /* failed; most likely cause is bad host name */
429                 tst = ADMCFGSERVERSETCELLFAILED;
430             }
431         }
432     }
433
434     if (tst != 0) {
435         rc = 0;
436     }
437     if (st != NULL) {
438         *st = tst;
439     }
440     return rc;
441 }
442
443
444 /*
445  * cfg_HostSetAfsPrincipal() -- Put AFS server principal (afs) key in
446  *     host's KeyFile; principal is created if it does not exist.
447  *
448  *     If first server host in cell, passwd must be initial password for
449  *     the afs principal; the afs principal is created.
450  *
451  *     If additional server host, passwd can be specified or NULL; the
452  *     afs principal must already exist by definition.  If passwd is NULL
453  *     then an attempt is made to fetch the afs key.  If the key fetch fails
454  *     because pre 3.5 database servers are in use (which will only return a
455  *     key checksum) then the function fails with a return status of
456  *     ADMCFGAFSKEYNOTAVAILABLE; in this case the function should be called
457  *     again with passwd specified.  If passwd is specified (not NULL) but the
458  *     password key fails a checksum comparison with the current afs key
459  *     then the function fails with a return status of ADMCFGAFSPASSWDINVALID.
460  *
461  * ASSUMPTIONS: Client configured and BOS server started; if first host in
462  *     cell then Authentication server must be started as well.
463  */
464 int ADMINAPI
465 cfg_HostSetAfsPrincipal(void *hostHandle,       /* host config handle */
466                         short isFirst,  /* first server in cell flag */
467                         const char *passwd,     /* afs initial password */
468                         afs_status_p st)
469 {                               /* completion status */
470     int rc = 1;
471     afs_status_t tst2, tst = 0;
472     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
473
474     /* validate parameters */
475
476     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
477         tst = tst2;
478     } else if ((isFirst && passwd == NULL)
479                || (passwd != NULL && *passwd == '\0')) {
480         tst = ADMCFGPASSWDNULL;
481     }
482
483     /* put afs key in host's KeyFile */
484
485     if (tst == 0) {
486         kas_identity_t afsIdentity;
487         kas_encryptionKey_t afsKey;
488         int afsKvno = 0;
489
490         strcpy(afsIdentity.principal, "afs");
491         afsIdentity.instance[0] = '\0';
492
493         if (isFirst) {
494             /* create afs principal */
495             if (!kas_PrincipalCreate
496                 (cfg_host->cellHandle, NULL, &afsIdentity, passwd, &tst2)
497                 && tst2 != KAEXIST) {
498                 /* failed to create principal (and not because existed) */
499                 tst = tst2;
500             }
501         }
502
503         if (tst == 0) {
504             /* retrive afs principal information to verify or obtain key */
505             kas_principalEntry_t afsEntry;
506
507             if (!kas_PrincipalGet
508                 (cfg_host->cellHandle, NULL, &afsIdentity, &afsEntry,
509                  &tst2)) {
510                 tst = tst2;
511             } else {
512                 if (passwd != NULL) {
513                     /* password given; form key and verify as most recent */
514                     kas_encryptionKey_t passwdKey;
515                     unsigned int passwdKeyCksum;
516
517                     if (!kas_StringToKey
518                         (cfg_host->cellName, passwd, &passwdKey, &tst2)
519                         || !kas_KeyCheckSum(&passwdKey, &passwdKeyCksum,
520                                             &tst2)) {
521                         /* failed to form key or key checksum */
522                         tst = tst2;
523
524                     } else if (passwdKeyCksum != afsEntry.keyCheckSum) {
525                         /* passwd string does not generate most recent key;
526                          * check if passwd string embeds key directly.
527                          */
528                         if (KasKeyEmbeddedInString(passwd, &passwdKey)) {
529                             /* passwd string embeds kas key */
530                             if (!kas_KeyCheckSum
531                                 (&passwdKey, &passwdKeyCksum, &tst2)) {
532                                 tst = tst2;
533                             } else if (passwdKeyCksum != afsEntry.keyCheckSum) {
534                                 /* passwd string does not embed valid key */
535                                 tst = ADMCFGAFSPASSWDINVALID;
536                             }
537                         } else {
538                             /* passwd string does NOT embed key */
539                             tst = ADMCFGAFSPASSWDINVALID;
540                         }
541                     }
542
543                     if (tst == 0) {
544                         /* passwd seems to generate/embed most recent key */
545                         afsKey = passwdKey;
546                         afsKvno = afsEntry.keyVersion;
547                     }
548
549                 } else {
550                     /* password NOT given; check if key retrieved since
551                      * pre 3.5 database servers only return key checksum
552                      */
553                     if (KasKeyIsZero(&afsEntry.key)) {
554                         tst = ADMCFGAFSKEYNOTAVAILABLE;
555                     } else {
556                         afsKey = afsEntry.key;
557                         afsKvno = afsEntry.keyVersion;
558                     }
559                 }
560             }
561         }
562
563         if (tst == 0) {
564             /* add key to host's KeyFile; RPC must be unauthenticated;
565              * bosserver is presumed to be in noauth mode.
566              */
567             void *cellHandle, *bosHandle;
568
569             if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
570                 tst = tst2;
571             } else {
572                 if (!bos_ServerOpen
573                     (cellHandle, cfg_host->hostName, &bosHandle, &tst2)) {
574                     tst = tst2;
575                 } else {
576                     if (!bos_KeyCreate(bosHandle, afsKvno, &afsKey, &tst2)
577                         && tst2 != BZKEYINUSE) {
578                         /* failed to add key (and not because existed) */
579                         tst = tst2;
580                     }
581
582                     if (!bos_ServerClose(bosHandle, &tst2)) {
583                         tst = tst2;
584                     }
585                 }
586
587                 if (!afsclient_CellClose(cellHandle, &tst2)) {
588                     tst = tst2;
589                 }
590             }
591         }
592     }
593
594     if (tst != 0) {
595         rc = 0;
596     }
597     if (st != NULL) {
598         *st = tst;
599     }
600     return rc;
601 }
602
603
604 /*
605  * cfg_HostSetAdminPrincipal() -- Put generic administrator principal in
606  *     host's UserList; principal is created if it does not exist.
607  *
608  *     If first server host in cell, passwd and afsUid must be the initial
609  *     password and the AFS UID for the admin principal; the admin principal
610  *     is created.
611  *
612  *     If additional server host, passwd and afsUid are ignored; the admin
613  *     principal is assumed to exist.
614  *
615  * ASSUMPTIONS: Client configured and BOS server started; if first host in
616  *     cell then Authentication and Protection servers must be started as well.
617  */
618 int ADMINAPI
619 cfg_HostSetAdminPrincipal(void *hostHandle,     /* host config handle */
620                           short isFirst,        /* first server in cell flag */
621                           char *admin,          /* admin principal name */
622                           const char *passwd,   /* admin initial password */
623                           unsigned int afsUid,  /* admin AFS UID */
624                           afs_status_p st)
625 {                               /* completion status */
626     int rc = 1;
627     afs_status_t tst2, tst = 0;
628     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
629
630     /* validate parameters and prepare host handle for bos functions */
631
632     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
633         tst = tst2;
634     } else if (admin == NULL || *admin == '\0') {
635         tst = ADMCFGADMINPRINCIPALNULL;
636     } else if (strlen(admin) > (KAS_MAX_NAME_LEN - 1)) {
637         tst = ADMCFGADMINPRINCIPALTOOLONG;
638     } else if (isFirst && (passwd == NULL || *passwd == '\0')) {
639         tst = ADMCFGPASSWDNULL;
640     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
641         tst = tst2;
642     }
643
644     /* put admin in host's UserList */
645
646     if (tst == 0) {
647         if (isFirst) {
648             /* first server host in cell; create admin principal */
649             kas_identity_t adminIdentity;
650             int adminUid = afsUid;
651             kas_admin_t adminFlag = KAS_ADMIN;
652
653             strcpy(adminIdentity.principal, admin);
654             adminIdentity.instance[0] = '\0';
655
656             if (!kas_PrincipalCreate
657                 (cfg_host->cellHandle, NULL, &adminIdentity, passwd, &tst2)
658                 && tst2 != KAEXIST) {
659                 /* failed to create principal (and not because existed) */
660                 tst = tst2;
661
662             } else
663                 if (!kas_PrincipalFieldsSet
664                     (cfg_host->cellHandle, NULL, &adminIdentity, &adminFlag,
665                      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
666                      &tst2)) {
667                 /* failed to set admin attributes */
668                 tst = tst2;
669
670             } else
671                 if (!pts_UserCreate
672                     (cfg_host->cellHandle, admin, &adminUid, &tst2)
673                     && tst2 != PREXIST) {
674                 /* failed to create user (and not because existed) */
675                 tst = tst2;
676
677             } else
678                 if (!pts_GroupMemberAdd
679                     (cfg_host->cellHandle, admin, "system:administrators",
680                      &tst2) && tst2 != PRIDEXIST) {
681                 /* failed to add to group (not because already there) */
682                 tst = tst2;
683             }
684         }
685
686         if (tst == 0) {
687             /* add admin to host's UserList */
688             if (!bos_AdminCreate(cfg_host->bosHandle, admin, &tst2)
689                 && tst2 != EEXIST) {
690                 /* failed to add admin (and not because existed) */
691                 /* DANGER: platform-specific errno values being returned */
692                 tst = tst2;
693             }
694         }
695     }
696
697     if (tst != 0) {
698         rc = 0;
699     }
700     if (st != NULL) {
701         *st = tst;
702     }
703     return rc;
704 }
705
706
707 /*
708  * cfg_HostInvalidate() -- Invalidate static server configuration on host.
709  *
710  *     Server configuration invalidated only if BOS server is not running.
711  */
712 int ADMINAPI
713 cfg_HostInvalidate(void *hostHandle,    /* host config handle */
714                    afs_status_p st)
715 {                               /* completion status */
716     int rc = 1;
717     afs_status_t tst2, tst = 0;
718     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
719
720     /* validate parameters */
721
722     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
723         tst = tst2;
724     }
725
726     /* remote configuration not yet supported in this function */
727
728     if (tst == 0) {
729         if (!cfg_host->is_local) {
730             tst = ADMCFGNOTSUPPORTED;
731         }
732     }
733
734     /* make sure bosserver is not running on host */
735
736 #ifdef AFS_NT40_ENV
737     /* Windows - bosserver is controlled via the BOS control service */
738     if (tst == 0) {
739         DWORD svcState;
740
741         if (!cfgutil_WindowsServiceQuery
742             (AFSREG_SVR_SVC_NAME, &svcState, &tst2)) {
743             tst = tst2;
744         } else if (svcState != SERVICE_STOPPED) {
745             tst = ADMCFGBOSSERVERACTIVE;
746         }
747     }
748 #else
749     if (tst == 0) {
750         /* function not yet implemented for Unix */
751         tst = ADMCFGNOTSUPPORTED;
752     }
753 #endif /* AFS_NT40_ENV */
754
755
756     /* remove server state files */
757
758     if (tst == 0) {
759         int i;
760         const char *cfgdir[3];
761
762         cfgdir[0] = AFSDIR_SERVER_ETC_DIRPATH;
763         cfgdir[1] = AFSDIR_SERVER_DB_DIRPATH;
764         cfgdir[2] = AFSDIR_SERVER_LOCAL_DIRPATH;
765
766         for (i = 0; i < 3 && tst == 0; i++) {
767             if (!cfgutil_CleanDirectory(cfgdir[i], &tst2)) {
768                 tst = tst2;
769             }
770         }
771     }
772
773     /* remove all vice partition table entries */
774
775 #ifdef AFS_NT40_ENV
776     if (tst == 0) {
777         struct vpt_iter vpiter;
778         struct vptab vpentry;
779
780         /* note: ignore errors except from removal attempts */
781
782         if (!vpt_Start(&vpiter)) {
783             while (!vpt_NextEntry(&vpiter, &vpentry)) {
784                 if (vpt_RemoveEntry(vpentry.vp_name)) {
785                     /* ENOENT implies entry does not exist; consider removed */
786                     if (errno != ENOENT) {
787                         if (errno == EACCES) {
788                             tst = ADMNOPRIV;
789                         } else {
790                             tst = ADMCFGVPTABLEWRITEFAILED;
791                         }
792                     }
793                 }
794             }
795             (void)vpt_Finish(&vpiter);
796         }
797     }
798 #else
799     /* function not yet implemented for unix */
800     if (tst == 0) {
801         tst = ADMCFGNOTSUPPORTED;
802     }
803 #endif /* AFS_NT40_ENV */
804
805     if (tst != 0) {
806         rc = 0;
807     }
808     if (st != NULL) {
809         *st = tst;
810     }
811     return rc;
812 }
813
814
815
816 /*
817  * cfg_HostPartitionTableEnumerate() -- Enumerate AFS partition table entries.
818  *
819  *     If the partition table is empty (or does not exist) then *tablePP
820  *     is set to NULL and *nEntriesP is set to zero (0).
821  *
822  *     Partitions in table are not necessarily those being exported; a table
823  *     entry may have been added or removed since the fileserver last started.
824  */
825 int ADMINAPI
826 cfg_HostPartitionTableEnumerate(void *hostHandle,       /* host config handle */
827                                 cfg_partitionEntry_t ** tablePP,        /* table */
828                                 int *nEntriesP, /* table entry count */
829                                 afs_status_p st)
830 {                               /* completion status */
831     int rc = 1;
832     afs_status_t tst2, tst = 0;
833     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
834
835     /* validate parameters */
836
837     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
838         tst = tst2;
839     } else if (tablePP == NULL) {
840         tst = ADMCFGVPTABLEPNULL;
841     } else if (nEntriesP == NULL) {
842         tst = ADMCFGVPTABLECOUNTPNULL;
843     }
844
845     /* remote configuration not yet supported in this function */
846
847     if (tst == 0) {
848         if (!cfg_host->is_local) {
849             tst = ADMCFGNOTSUPPORTED;
850         }
851     }
852
853     /* enumerate the vice partition table */
854
855 #ifdef AFS_NT40_ENV
856     if (tst == 0) {
857         struct vpt_iter vpiter;
858         struct vptab vpentry;
859         int vpentryCountMax = 0;
860
861         /* count table entries */
862
863         if (vpt_Start(&vpiter)) {
864             /* ENOENT implies table does not exist (which is OK) */
865             if (errno != ENOENT) {
866                 if (errno == EACCES) {
867                     tst = ADMNOPRIV;
868                 } else {
869                     tst = ADMCFGVPTABLEREADFAILED;
870                 }
871             }
872         } else {
873             while (!vpt_NextEntry(&vpiter, &vpentry)) {
874                 vpentryCountMax++;
875             }
876             if (errno != ENOENT) {
877                 tst = ADMCFGVPTABLEREADFAILED;
878             }
879             (void)vpt_Finish(&vpiter);
880         }
881
882         /* alloc storage for table entries; handle any entry count change */
883
884         if (tst == 0) {
885             if (vpentryCountMax == 0) {
886                 *nEntriesP = 0;
887                 *tablePP = NULL;
888             } else {
889                 /* return a two-part table; first points into second */
890                 void *metaTablep;
891                 size_t metaTableSize;
892
893                 metaTableSize =
894                     vpentryCountMax * (sizeof(cfg_partitionEntry_t) +
895                                        sizeof(struct vptab));
896
897                 if ((metaTablep = (void *)malloc(metaTableSize)) == NULL) {
898                     tst = ADMNOMEM;
899                 } else {
900                     int i;
901                     cfg_partitionEntry_t *cpePart;
902                     struct vptab *vptPart;
903                     int vpentryCount = 0;
904
905                     cpePart = (cfg_partitionEntry_t *) metaTablep;
906                     vptPart = (struct vptab *)(&cpePart[vpentryCountMax]);
907
908                     for (i = 0; i < vpentryCountMax; i++) {
909                         cpePart[i].partitionName = vptPart[i].vp_name;
910                         cpePart[i].deviceName = vptPart[i].vp_dev;
911                     }
912
913                     if (vpt_Start(&vpiter)) {
914                         /* ENOENT implies table does not exist (which is OK) */
915                         if (errno != ENOENT) {
916                             if (errno == EACCES) {
917                                 tst = ADMNOPRIV;
918                             } else {
919                                 tst = ADMCFGVPTABLEREADFAILED;
920                             }
921                         }
922                     } else {
923                         for (i = 0; i < vpentryCountMax; i++) {
924                             if (vpt_NextEntry(&vpiter, &vptPart[i])) {
925                                 break;
926                             }
927                         }
928
929                         if (i < vpentryCountMax && errno != ENOENT) {
930                             tst = ADMCFGVPTABLEREADFAILED;
931                         } else {
932                             vpentryCount = i;
933                         }
934                         (void)vpt_Finish(&vpiter);
935                     }
936
937                     if (tst == 0) {
938                         *nEntriesP = vpentryCount;
939
940                         if (vpentryCount != 0) {
941                             *tablePP = (cfg_partitionEntry_t *) metaTablep;
942                         } else {
943                             *tablePP = NULL;
944                             free(metaTablep);
945                         }
946                     } else {
947                                 free(metaTablep);
948                     }
949                 }
950             }
951         }
952     }
953 #else
954     /* function not yet implemented for Unix */
955     if (tst == 0) {
956         tst = ADMCFGNOTSUPPORTED;
957     }
958 #endif /* AFS_NT40_ENV */
959
960     if (tst != 0) {
961         rc = 0;
962     }
963     if (st != NULL) {
964         *st = tst;
965     }
966     return rc;
967 }
968
969
970 /*
971  * cfg_HostPartitionTableAddEntry() -- Add or update AFS partition table entry.
972  */
973 int ADMINAPI
974 cfg_HostPartitionTableAddEntry(void *hostHandle,        /* host config handle */
975                                const char *partName,    /* partition name */
976                                const char *devName,     /* device name */
977                                afs_status_p st)
978 {                               /* completion status */
979     int rc = 1;
980     afs_status_t tst = 0;
981 #ifdef AFS_NT40_ENV
982     afs_status_t tst2;
983     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
984 #endif
985
986 #ifdef AFS_NT40_ENV
987     /* validate parameters */
988
989     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
990         tst = tst2;
991     } else if (partName == NULL) {
992         tst = ADMCFGPARTITIONNAMENULL;
993     } else if (!vpt_PartitionNameValid(partName)) {
994         tst = ADMCFGPARTITIONNAMEBAD;
995     } else if (devName == NULL) {
996         tst = ADMCFGDEVICENAMENULL;
997     } else if (!vpt_DeviceNameValid(devName)) {
998         tst = ADMCFGDEVICENAMEBAD;
999     }
1000
1001     /* remote configuration not yet supported in this function */
1002
1003     if (tst == 0) {
1004         if (!cfg_host->is_local) {
1005             tst = ADMCFGNOTSUPPORTED;
1006         }
1007     }
1008
1009     /* add entry to table */
1010
1011     if (tst == 0) {
1012         struct vptab vpentry;
1013
1014         strcpy(vpentry.vp_name, partName);
1015         strcpy(vpentry.vp_dev, devName);
1016
1017         if (vpt_AddEntry(&vpentry)) {
1018             if (errno == EACCES) {
1019                 tst = ADMNOPRIV;
1020             } else if (errno == EINVAL) {
1021                 /* shouldn't happen since checked partition/dev names */
1022                 tst = ADMCFGVPTABLEENTRYBAD;
1023             } else {
1024                 tst = ADMCFGVPTABLEWRITEFAILED;
1025             }
1026         }
1027     }
1028 #else
1029     /* function not yet implemented for unix */
1030     if (tst == 0) {
1031         tst = ADMCFGNOTSUPPORTED;
1032     }
1033 #endif /* AFS_NT40_ENV */
1034
1035     if (tst != 0) {
1036         rc = 0;
1037     }
1038     if (st != NULL) {
1039         *st = tst;
1040     }
1041     return rc;
1042 }
1043
1044
1045 /*
1046  * cfg_HostPartitionTableRemoveEntry() -- Remove AFS partition table entry.
1047  */
1048 int ADMINAPI
1049 cfg_HostPartitionTableRemoveEntry(void *hostHandle,     /* host config handle */
1050                                   const char *partName, /* partition name */
1051                                   afs_status_p st)
1052 {                               /* completion status */
1053     int rc = 1;
1054     afs_status_t tst = 0;
1055 #ifdef AFS_NT40_ENV
1056     afs_status_t tst2;
1057     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1058 #endif
1059
1060 #ifdef AFS_NT40_ENV
1061     /* validate parameters */
1062
1063     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1064         tst = tst2;
1065     } else if (partName == NULL) {
1066         tst = ADMCFGPARTITIONNAMENULL;
1067     } else if (!vpt_PartitionNameValid(partName)) {
1068         tst = ADMCFGPARTITIONNAMEBAD;
1069     }
1070
1071     /* remote configuration not yet supported in this function */
1072
1073     if (tst == 0) {
1074         if (!cfg_host->is_local) {
1075             tst = ADMCFGNOTSUPPORTED;
1076         }
1077     }
1078
1079     /* remove entry from table */
1080
1081     if (tst == 0) {
1082         if (vpt_RemoveEntry(partName)) {
1083             /* ENOENT implies entry does not exist; consider to be removed */
1084             if (errno != ENOENT) {
1085                 if (errno == EACCES) {
1086                     tst = ADMNOPRIV;
1087                 } else if (errno == EINVAL) {
1088                     /* shouldn't happen since checked partition/dev names */
1089                     tst = ADMCFGPARTITIONNAMEBAD;
1090                 } else {
1091                     tst = ADMCFGVPTABLEWRITEFAILED;
1092                 }
1093             }
1094         }
1095     }
1096 #else
1097     /* function not yet implemented for unix */
1098     if (tst == 0) {
1099         tst = ADMCFGNOTSUPPORTED;
1100     }
1101 #endif /* AFS_NT40_ENV */
1102
1103     if (tst != 0) {
1104         rc = 0;
1105     }
1106     if (st != NULL) {
1107         *st = tst;
1108     }
1109     return rc;
1110 }
1111
1112
1113 /*
1114  * cfg_HostPartitionNameValid() -- check partition name syntax.
1115  */
1116 int ADMINAPI
1117 cfg_HostPartitionNameValid(const char *partName,        /* partition name */
1118                            short *isValidP,     /* syntax is valid */
1119                            afs_status_p st)
1120 {                               /* completion status */
1121     int rc = 1;
1122     afs_status_t tst = 0;
1123
1124     /* validate parameters */
1125
1126     if (partName == NULL) {
1127         tst = ADMCFGPARTITIONNAMENULL;
1128     } else if (isValidP == NULL) {
1129         tst = ADMCFGVALIDFLAGPNULL;
1130     }
1131
1132     /* check name syntax */
1133
1134 #ifdef AFS_NT40_ENV
1135     if (tst == 0) {
1136         *isValidP = vpt_PartitionNameValid(partName);
1137     }
1138 #else
1139     /* function not yet implemented for Unix */
1140     if (tst == 0) {
1141         tst = ADMCFGNOTSUPPORTED;
1142     }
1143 #endif
1144
1145     if (tst != 0) {
1146         rc = 0;
1147     }
1148     if (st != NULL) {
1149         *st = tst;
1150     }
1151     return rc;
1152 }
1153
1154
1155
1156 /*
1157  * cfg_HostDeviceNameValid() -- check device name syntax.
1158  */
1159 int ADMINAPI
1160 cfg_HostDeviceNameValid(const char *devName,    /* device name */
1161                         short *isValidP,        /* syntax is valid */
1162                         afs_status_p st)
1163 {                               /* completion status */
1164     int rc = 1;
1165     afs_status_t tst = 0;
1166
1167     /* validate parameters */
1168
1169     if (devName == NULL) {
1170         tst = ADMCFGDEVICENAMENULL;
1171     } else if (isValidP == NULL) {
1172         tst = ADMCFGVALIDFLAGPNULL;
1173     }
1174
1175     /* check name syntax */
1176
1177 #ifdef AFS_NT40_ENV
1178     if (tst == 0) {
1179         *isValidP = vpt_DeviceNameValid(devName);
1180     }
1181 #else
1182     /* function not yet implemented for Unix */
1183     if (tst == 0) {
1184         tst = ADMCFGNOTSUPPORTED;
1185     }
1186 #endif
1187
1188     if (tst != 0) {
1189         rc = 0;
1190     }
1191     if (st != NULL) {
1192         *st = tst;
1193     }
1194     return rc;
1195 }
1196
1197
1198
1199 /* ---------------- Exported Utility functions ------------------ */
1200
1201
1202 /*
1203  * cfg_StringDeallocate() -- Deallocate (multi)string returned by library.
1204  */
1205 int ADMINAPI
1206 cfg_StringDeallocate(char *stringDataP, /* (multi)string to deallocate */
1207                      afs_status_p st)
1208 {                               /* completion status */
1209     free(stringDataP);
1210     if (st != NULL) {
1211         *st = 0;
1212     }
1213     return 1;
1214 }
1215
1216
1217 /*
1218  * cfg_PartitionListDeallocate() -- Deallocate partition table enumeration
1219  *     returned by library.
1220  */
1221 int ADMINAPI
1222 cfg_PartitionListDeallocate(cfg_partitionEntry_t * partitionListDataP,
1223                             afs_status_p st)
1224 {
1225     free(partitionListDataP);
1226     if (st != NULL) {
1227         *st = 0;
1228     }
1229     return 1;
1230 }
1231
1232
1233
1234
1235 /* ---------------- Local functions ------------------ */
1236
1237
1238 /*
1239  * KasKeyIsZero() -- determine if kas key is zero
1240  *
1241  * RETURN CODES: 1 if zero, 0 otherwise
1242  */
1243 static int
1244 KasKeyIsZero(kas_encryptionKey_t * kasKey)
1245 {
1246     char *keyp = (char *)kasKey;
1247     int i;
1248
1249     for (i = 0; i < sizeof(*kasKey); i++) {
1250         if (*keyp++ != 0) {
1251             return 0;
1252         }
1253     }
1254     return 1;
1255 }
1256
1257
1258 /*
1259  * KasKeyEmbeddedInString() -- determine if kas key is embedded in string
1260  *     and return key if extant.
1261  *
1262  * RETURN CODES: 1 if embedded key found, 0 otherwise
1263  */
1264 static int
1265 KasKeyEmbeddedInString(const char *keyString, kas_encryptionKey_t * kasKey)
1266 {
1267     char *octalDigits = "01234567";
1268
1269     /* keyString format is exactly 24 octal digits if embeds kas key */
1270     if (strlen(keyString) == 24 && strspn(keyString, octalDigits) == 24) {
1271         /* kas key is embedded in keyString; extract it */
1272         int i;
1273
1274         for (i = 0; i < 24; i += 3) {
1275             char keyPiece[4];
1276             unsigned char keyPieceVal;
1277
1278             keyPiece[0] = keyString[i];
1279             keyPiece[1] = keyString[i + 1];
1280             keyPiece[2] = keyString[i + 2];
1281             keyPiece[3] = '\0';
1282
1283             keyPieceVal = (unsigned char)strtoul(keyPiece, NULL, 8);
1284
1285             *((unsigned char *)kasKey + (i / 3)) = keyPieceVal;
1286         }
1287         return 1;
1288     } else {
1289         /* key NOT embedded in keyString */
1290         return 0;
1291     }
1292 }