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