Import Upstream version 1.8.5
[hcoop/debian/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 = 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 = 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 }