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