windows-cellconfig-20090630
[openafs.git] / src / WINNT / afsd / cm_config.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 #include <windows.h>
11 #include <winsock2.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15
16 #include "afsd.h"
17 #include <WINNT\afssw.h>
18 #include <WINNT\afsreg.h>
19
20 #include <afs/param.h>
21 #include <afs/stds.h>
22 #include <afs/cellconfig.h>
23
24 #ifdef AFS_AFSDB_ENV
25 #include "cm_dns.h"
26 #include <afs/afsint.h>
27 #endif
28
29 static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
30 {
31     char *tp;
32     char tc;
33     int sawEquals;
34     int sawBracket;
35         
36     sawEquals = 0;
37     sawBracket = 0;
38     for(tp = lineBufferp; *tp; tp++) {
39         tc = *tp;
40
41         if (sawBracket) {
42             if (tc == ']')
43                 sawBracket = 0;
44             continue;
45         }
46
47         /* comment or line end */
48         if (tc == '#' || tc == '\r' || tc == '\n') 
49             break;
50
51         /* square bracket comment -- look for closing delim */
52         if (tc == '[') {
53             sawBracket = 1; 
54             continue;
55         }       
56
57         /* space or tab */
58         if (tc == ' ' || tc == '\t') 
59             continue;
60
61         if (tc == '=') {
62             sawEquals = 1;
63             continue;
64         }
65
66         /* now we have a real character, put it in the appropriate bucket */
67         if (sawEquals == 0) {
68             *leftp++ = tc;
69         }       
70         else {  
71             *rightp++ = tc;
72         }
73     }
74
75     /* null terminate the strings */
76     *leftp = 0;
77     *rightp = 0;
78
79     return 0;   /* and return success */
80 }
81
82 static int
83 IsWindowsModule(const char * name)
84 {
85     const char * p;
86     int i;
87
88     /* Do not perform searches for probable Windows modules */
89     for (p = name, i=0; *p; p++) {
90         if ( *p == '.' )
91             i++;
92     }
93     p = strrchr(name, '.');
94     if (p) {
95         if (i == 1 && 
96             (!cm_stricmp_utf8N(p,".dll") ||
97              !cm_stricmp_utf8N(p,".exe") ||
98              !cm_stricmp_utf8N(p,".ini") ||
99              !cm_stricmp_utf8N(p,".db") ||
100              !cm_stricmp_utf8N(p,".drv")))
101             return 1;
102     }
103     return 0;
104 }
105
106 /* search for a cell, and either return an error code if we don't find it,
107  * or return 0 if we do, in which case we also fill in the addresses in
108  * the cellp field.
109  *
110  * new feature:  we can handle abbreviations and are insensitive to case.
111  * If the caller wants the "real" cell name, it puts a non-null pointer in
112  * newCellNamep.  Anomaly:  if cellNamep is ambiguous, we may modify
113  * newCellNamep but return an error code.
114  *
115  * Linked Cells: the CellServDB format permits linked cells
116  *   >cell [linked-cell] #Description
117  *
118  * newCellNamep and linkedNamep are required to be CELL_MAXNAMELEN in size.
119  */
120 long cm_SearchCellFile(char *cellNamep, char *newCellNamep,
121                        cm_configProc_t *procp, void *rockp)
122 {
123     return cm_SearchCellFileEx(cellNamep, newCellNamep, NULL, procp, rockp);
124 }
125
126 long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
127                          char *linkedNamep,
128                          cm_configProc_t *procp, void *rockp)
129 {
130     char wdir[MAX_PATH]="";
131     FILE *tfilep = NULL, *bestp, *tempp;
132     char *tp, *linkp;
133     char lineBuffer[257];
134     struct hostent *thp;
135     char *valuep;
136     struct sockaddr_in vlSockAddr;
137     int inRightCell = 0;
138     int foundCell = 0;
139     long code;
140     int tracking = 1, partial = 0;
141
142     if ( IsWindowsModule(cellNamep) )
143         return -3;
144
145     cm_GetCellServDB(wdir, sizeof(wdir));
146     if (*wdir)
147         tfilep = fopen(wdir, "r");
148
149     if (!tfilep) 
150         return -2;
151
152     bestp = fopen(wdir, "r");
153     
154 #ifdef CELLSERV_DEBUG
155     osi_Log2(afsd_logp,"cm_searchfile fopen handle[%p], wdir[%s]", bestp, 
156              osi_LogSaveString(afsd_logp,wdir));
157 #endif
158     /* have we seen the cell line for the guy we're looking for? */
159     while (1) {
160         linkp = NULL;
161         tp = fgets(lineBuffer, sizeof(lineBuffer), tfilep);
162         if (tracking)
163             (void) fgets(lineBuffer, sizeof(lineBuffer), bestp);
164         if (tp == NULL) {
165             if (feof(tfilep)) {
166                 /* hit EOF */
167                 if (partial) {
168                     /*
169                      * found partial match earlier;
170                      * now go back to it
171                      */
172                     tempp = bestp;
173                     bestp = tfilep;
174                     tfilep = tempp;
175                     inRightCell = 1;
176                     partial = 0;
177                     continue;
178                 }
179                 else {
180                     fclose(tfilep);
181                     fclose(bestp);
182                     return (foundCell? 0 : -3);
183                 }
184             }
185         }       
186
187         /* turn trailing cr or lf into null */
188         tp = strrchr(lineBuffer, '\r');
189         if (tp) *tp = 0;
190         tp = strrchr(lineBuffer, '\n');
191         if (tp) *tp = 0;
192
193         /* skip blank lines */
194         if (lineBuffer[0] == 0) continue;
195
196         /*
197          * The format is:
198          *   >[cell] [linked-cell] #[Description]
199          * where linked-cell and Description are optional
200          */
201         if (lineBuffer[0] == '>') {
202             if (inRightCell) {
203                 fclose(tfilep);
204                 fclose(bestp);
205                 return(foundCell ? 0 : -6);
206             }
207
208             /* 
209              * terminate the cellname at the first white space
210              * leaving 'tp' pointing to the next string if any
211              */
212             for (tp = &lineBuffer[1]; tp && !isspace(*tp); tp++);
213             if (tp) {
214                 *tp = '\0';
215                 for (tp++ ;tp && isspace(*tp); tp++);
216                 if (*tp != '#') {
217                     linkp = tp;
218                     for (; tp && !isspace(*tp); tp++);
219                     if (tp) 
220                         *tp = '\0';
221                 }
222             }
223
224             /* now see if this is the right cell */
225             if (stricmp(lineBuffer+1, cellNamep) == 0) {
226                 /* found the cell we're looking for */
227                 if (newCellNamep) {
228                     strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
229                     newCellNamep[CELL_MAXNAMELEN-1] = '\0';
230                     strlwr(newCellNamep);
231                 }
232                 if (linkedNamep) {
233                     strncpy(linkedNamep, linkp ? linkp : "", CELL_MAXNAMELEN);
234                     linkedNamep[CELL_MAXNAMELEN-1] = '\0';
235                     strlwr(linkedNamep);
236                 }
237                 inRightCell = 1;
238                 tracking = 0;
239 #ifdef CELLSERV_DEBUG                
240                 osi_Log2(afsd_logp, "cm_searchfile is cell inRightCell[%p], linebuffer[%s]",
241                          inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
242 #endif
243             }
244             else if (cm_stricmp_utf8(lineBuffer+1, cellNamep) == 0) {
245                 /* partial match */
246                 if (partial) {  /* ambiguous */
247                     fclose(tfilep);
248                     fclose(bestp);
249                     return -5;
250                 }
251                 if (newCellNamep) {
252                     strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
253                     newCellNamep[CELL_MAXNAMELEN-1] = '\0';
254                     strlwr(newCellNamep);
255                 }
256                 if (linkedNamep) {
257                     strncpy(linkedNamep, linkp ? linkp : "", CELL_MAXNAMELEN);
258                     linkedNamep[CELL_MAXNAMELEN-1] = '\0';
259                     strlwr(linkedNamep);
260                 }
261                 inRightCell = 0;
262                 tracking = 0;
263                 partial = 1;
264             }
265             else inRightCell = 0;
266         }
267         else {
268             valuep = strchr(lineBuffer, '#');
269             if (valuep == NULL) {
270                 fclose(tfilep);
271                 fclose(bestp);
272                 return -4;
273             }
274             valuep++;   /* skip the "#" */
275
276             valuep += strspn(valuep, " \t"); /* skip SP & TAB */
277             /* strip spaces and tabs in the end. They should not be there according to CellServDB format
278              * so do this just in case                        
279              */
280             while (valuep[strlen(valuep) - 1] == ' ' || valuep[strlen(valuep) - 1] == '\t') 
281                 valuep[strlen(valuep) - 1] = '\0';
282
283             if (inRightCell) {
284                 char hostname[256];
285                 int  i, isClone = 0;
286
287                 isClone = (lineBuffer[0] == '[');
288
289                 /* copy just the first word and ignore trailing white space */
290                 for ( i=0; valuep[i] && !isspace(valuep[i]) && i<sizeof(hostname); i++)
291                     hostname[i] = valuep[i];
292                 hostname[i] = '\0';
293
294                 /* add the server to the VLDB list */
295                 WSASetLastError(0);
296                 thp = gethostbyname(hostname);
297 #ifdef CELLSERV_DEBUG
298                 osi_Log3(afsd_logp,"cm_searchfile inRightCell thp[%p], valuep[%s], WSAGetLastError[%d]",
299                          thp, osi_LogSaveString(afsd_logp,hostname), WSAGetLastError());
300 #endif
301                 if (thp) {
302                     int foundAddr = 0;
303                     for (i=0 ; thp->h_addr_list[i]; i++) {
304                         if (thp->h_addrtype != AF_INET)
305                             continue;
306                         memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr_list[i],
307                                sizeof(long));
308                         vlSockAddr.sin_family = AF_INET;
309                         /* sin_port supplied by connection code */
310                         if (procp)
311                             (*procp)(rockp, &vlSockAddr, hostname, 0);
312                         foundAddr = 1;
313                     }
314                     /* if we didn't find a valid address, force the use of the specified one */
315                     if (!foundAddr)
316                         thp = NULL;
317                 }
318                 if (!thp) {
319                     afs_uint32 ip_addr;
320                     unsigned int c1, c2, c3, c4;
321                     
322                     /* Since there is no gethostbyname() data 
323                      * available we will read the IP address
324                      * stored in the CellServDB file
325                      */
326                     if (isClone)
327                         code = sscanf(lineBuffer, "[%u.%u.%u.%u]",
328                                       &c1, &c2, &c3, &c4);
329                     else
330                         code = sscanf(lineBuffer, " %u.%u.%u.%u",
331                                       &c1, &c2, &c3, &c4);
332                     if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
333                         tp = (unsigned char *) &ip_addr;
334                         *tp++ = c1;
335                         *tp++ = c2;
336                         *tp++ = c3;
337                         *tp++ = c4;
338                         memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
339                                 sizeof(long));
340                         vlSockAddr.sin_family = AF_INET;
341                         /* sin_port supplied by connection code */
342                         if (procp)
343                             (*procp)(rockp, &vlSockAddr, hostname, 0);
344                     }
345                 }
346                 foundCell = 1;
347             }
348         }       /* a vldb line */
349     }           /* while loop processing all lines */
350
351     /* if for some unknown reason cell is not found, return negative code (-11) ??? */
352     return (foundCell) ? 0 : -11;
353 }
354
355 /*
356  * The CellServDB registry schema is as follows:
357  *
358  * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\
359  *   "LinkedCell"    REG_SZ "[cellname]" 
360  *   "Description"   REG_SZ "[comment]"
361  *   "ForceDNS"      DWORD  {0,1}
362  *
363  * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\[servername]\
364  *   "HostName"      REG_SZ "[hostname]" 
365  *   "IPv4Address"   REG_SZ "[address]" 
366  *   "IPv6Address"   REG_SZ "[address]"   <future>
367  *   "Comment"       REG_SZ "[comment]"
368  *   "Rank"          DWORD  "0..65535"
369  *   "Clone"         DWORD  "{0,1}"
370  *   "vlserver"      DWORD  "7003"        <future>
371  *   "ptserver"      DWORD  ...           <future>
372  *
373  * ForceDNS is implied non-zero if there are no [servername]
374  * keys under the [cellname] key.  Otherwise, ForceDNS is zero.
375  * If [servername] keys are specified and none of them evaluate
376  * to a valid server configuration, the return code is success.
377  * This prevents failover to the CellServDB file or DNS.
378  */
379 long cm_SearchCellRegistry(afs_uint32 client, 
380                            char *cellNamep, char *newCellNamep,
381                            char *linkedNamep,
382                            cm_configProc_t *procp, void *rockp)
383 {
384     HKEY hkCellServDB = 0, hkCellName = 0, hkServerName = 0;
385     DWORD dwType, dwSize;
386     DWORD dwCells, dwServers, dwForceDNS;
387     DWORD dwIndex, dwRank;
388     unsigned short ipRank;
389     LONG code;
390     FILETIME ftLastWriteTime;
391     char szCellName[CELL_MAXNAMELEN];
392     char szServerName[MAXHOSTCHARS];
393     char szHostName[MAXHOSTCHARS];
394     char szAddr[64];
395     struct hostent *thp;
396     struct sockaddr_in vlSockAddr;
397     char * s;
398
399     if ( IsWindowsModule(cellNamep) )
400         return -1;
401
402     /* No Server CellServDB list (yet) */
403     if ( !client )
404         return CM_ERROR_NOSUCHCELL;
405
406     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
407                       AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
408                       0,
409                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
410                       &hkCellServDB) != ERROR_SUCCESS)
411         return CM_ERROR_NOSUCHCELL;
412
413     if (RegOpenKeyEx( hkCellServDB, 
414                       cellNamep,
415                       0,
416                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
417                       &hkCellName) != ERROR_SUCCESS) {
418         BOOL bFound = 0;
419
420         /* We did not find an exact match.  Much search for partial matches. */
421
422         code = RegQueryInfoKey( hkCellServDB,
423                                 NULL,  /* lpClass */
424                                 NULL,  /* lpcClass */
425                                 NULL,  /* lpReserved */
426                                 &dwCells,  /* lpcSubKeys */
427                                 NULL,  /* lpcMaxSubKeyLen */
428                                 NULL,  /* lpcMaxClassLen */
429                                 NULL,  /* lpcValues */
430                                 NULL,  /* lpcMaxValueNameLen */
431                                 NULL,  /* lpcMaxValueLen */
432                                 NULL,  /* lpcbSecurityDescriptor */
433                                 &ftLastWriteTime /* lpftLastWriteTime */
434                                 );
435         if (code != ERROR_SUCCESS)
436             dwCells = 0;
437
438         /* 
439          * We search the entire list to ensure that there is only
440          * one prefix match.  If there is more than one, we return none.
441          */
442         for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
443             dwSize = CELL_MAXNAMELEN;
444             code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
445                                  NULL, NULL, &ftLastWriteTime);
446             if (code != ERROR_SUCCESS)
447                 continue;
448             szCellName[CELL_MAXNAMELEN-1] = '\0';
449             strlwr(szCellName);
450
451             /* if not a prefix match, try the next key */
452             if (strncmp(cellNamep, szCellName, strlen(cellNamep)))
453                 continue;
454
455             /* If we have a prefix match and we already found another
456              * match, return neither */
457             if (hkCellName) {
458                 bFound = 0;
459                 RegCloseKey( hkCellName);
460                 break;
461             }
462
463             if (RegOpenKeyEx( hkCellServDB, 
464                               szCellName,
465                               0,
466                               KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
467                               &hkCellName) != ERROR_SUCCESS)
468                 continue;
469
470             if (newCellNamep) {
471                 strncpy(newCellNamep, szCellName, CELL_MAXNAMELEN);
472                 newCellNamep[CELL_MAXNAMELEN-1] = '\0';
473             }
474             bFound = 1;
475         }
476
477         if ( !bFound ) {
478             RegCloseKey(hkCellServDB);
479             return CM_ERROR_NOSUCHCELL;
480         }
481     } else if (newCellNamep) {
482         strncpy(newCellNamep, cellNamep, CELL_MAXNAMELEN);
483         newCellNamep[CELL_MAXNAMELEN-1] = '\0';
484         strlwr(newCellNamep);
485     }
486
487     if (linkedNamep) {
488         dwSize = CELL_MAXNAMELEN;
489         code = RegQueryValueEx(hkCellName, "LinkedCell", NULL, &dwType,
490                                 (BYTE *) linkedNamep, &dwSize);
491         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
492             linkedNamep[CELL_MAXNAMELEN-1] = '\0';
493             strlwr(linkedNamep);
494         } else {
495             linkedNamep[0] = '\0';
496         }
497     }
498
499     /* Check to see if DNS lookups are required */
500     dwSize = sizeof(DWORD);
501     code = RegQueryValueEx(hkCellName, "ForceDNS", NULL, &dwType,
502                             (BYTE *) &dwForceDNS, &dwSize);
503     if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
504         if (dwForceDNS)
505             goto done;
506     } else {
507         dwForceDNS = 0;
508     }
509
510     /* 
511      * Using the defined server list.  Enumerate and populate
512      * the server list for the cell.
513      */
514     code = RegQueryInfoKey( hkCellName,
515                             NULL,  /* lpClass */
516                             NULL,  /* lpcClass */
517                             NULL,  /* lpReserved */
518                             &dwServers,  /* lpcSubKeys */
519                             NULL,  /* lpcMaxSubKeyLen */
520                             NULL,  /* lpcMaxClassLen */
521                             NULL,  /* lpcValues */
522                             NULL,  /* lpcMaxValueNameLen */
523                             NULL,  /* lpcMaxValueLen */
524                             NULL,  /* lpcbSecurityDescriptor */
525                             &ftLastWriteTime /* lpftLastWriteTime */
526                             );
527     if (code != ERROR_SUCCESS)
528         dwServers = 0;
529
530     for ( dwIndex = 0; dwIndex < dwServers; dwIndex++ ) {
531         dwSize = MAXHOSTCHARS;
532         code = RegEnumKeyEx( hkCellName, dwIndex, szServerName, &dwSize, NULL, 
533                              NULL, NULL, &ftLastWriteTime);
534         if (code != ERROR_SUCCESS)
535             continue;
536
537         szServerName[MAXHOSTCHARS-1] = '\0';
538         if (RegOpenKeyEx( hkCellName, 
539                           szServerName,
540                           0,
541                           KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
542                           &hkServerName) != ERROR_SUCCESS)
543             continue;
544
545         /* We have a handle to a valid server key.  Now we need 
546          * to add the server to the cell */
547         
548         /* First, see if there is an alternate hostname specified */
549         dwSize = MAXHOSTCHARS;
550         code = RegQueryValueEx(hkServerName, "HostName", NULL, &dwType,
551                                 (BYTE *) szHostName, &dwSize);
552         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
553             szHostName[MAXHOSTCHARS-1] = '\0';
554             strlwr(szHostName);
555             s = szHostName;
556         } else {
557             s = szServerName;
558         }
559
560         dwSize = sizeof(DWORD);
561         code = RegQueryValueEx(hkServerName, "Rank", NULL, &dwType,
562                                 (BYTE *) &dwRank, &dwSize);
563         if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
564             ipRank = (unsigned short)(dwRank <= 65535 ? dwRank : 65535);
565         } else {
566             ipRank = 0;
567         }
568
569         dwSize = sizeof(szAddr);
570         code = RegQueryValueEx(hkServerName, "IPv4Address", NULL, &dwType,
571                                 (BYTE *) szAddr, &dwSize);
572         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
573             szAddr[63] = '\0';
574         } else {
575             szAddr[0] = '\0';
576         }
577
578         WSASetLastError(0);
579         thp = gethostbyname(s);
580         if (thp) {
581             memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr, sizeof(long));
582             vlSockAddr.sin_family = AF_INET;
583             /* sin_port supplied by connection code */
584             if (procp)
585                 (*procp)(rockp, &vlSockAddr, s, ipRank);
586         } else if (szAddr[0]) {
587             afs_uint32 ip_addr;
588             unsigned int c1, c2, c3, c4;
589
590             /* Since there is no gethostbyname() data 
591              * available we will read the IP address
592              * stored in the CellServDB file
593              */
594             code = sscanf(szAddr, " %u.%u.%u.%u",
595                            &c1, &c2, &c3, &c4);
596             if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
597                 unsigned char * tp = (unsigned char *) &ip_addr;
598                 *tp++ = c1;
599                 *tp++ = c2;
600                 *tp++ = c3;
601                 *tp++ = c4;
602                 memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
603                         sizeof(long));
604                 vlSockAddr.sin_family = AF_INET;
605                 /* sin_port supplied by connection code */
606                 if (procp)
607                     (*procp)(rockp, &vlSockAddr, s, ipRank);
608             }
609         }
610
611         RegCloseKey( hkServerName);
612     }
613
614   done:
615     RegCloseKey(hkCellName);
616     RegCloseKey(hkCellServDB);
617
618     return ((dwForceDNS || dwServers == 0) ? CM_ERROR_FORCE_DNS_LOOKUP : 0);
619 }
620
621 long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *procp, void *rockp)
622 {
623     HKEY hkCellServDB = 0;
624     DWORD dwType, dwSize;
625     DWORD dwCells;
626     DWORD dwIndex;
627     LONG code;
628     FILETIME ftLastWriteTime;
629     char szCellName[CELL_MAXNAMELEN];
630
631     /* No server CellServDB in the registry. */
632     if (!client || procp == NULL)
633         return 0;
634
635     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
636                       AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
637                       0,
638                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
639                       &hkCellServDB) != ERROR_SUCCESS)
640         return 0;
641
642     code = RegQueryInfoKey( hkCellServDB,
643                             NULL,  /* lpClass */
644                             NULL,  /* lpcClass */
645                             NULL,  /* lpReserved */
646                             &dwCells,  /* lpcSubKeys */
647                             NULL,  /* lpcMaxSubKeyLen */
648                             NULL,  /* lpcMaxClassLen */
649                             NULL,  /* lpcValues */
650                             NULL,  /* lpcMaxValueNameLen */
651                             NULL,  /* lpcMaxValueLen */
652                             NULL,  /* lpcbSecurityDescriptor */
653                             &ftLastWriteTime /* lpftLastWriteTime */
654                             );
655     if (code != ERROR_SUCCESS)
656         dwCells = 0;
657
658     /* 
659      * Enumerate each Cell and 
660      */
661     for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
662         dwSize = CELL_MAXNAMELEN;
663         code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
664                              NULL, NULL, &ftLastWriteTime);
665         if (code != ERROR_SUCCESS)
666             continue;
667         szCellName[CELL_MAXNAMELEN-1] = '\0';
668         strlwr(szCellName);
669
670         (*procp)(rockp, szCellName);
671     }
672
673     RegCloseKey(hkCellServDB);
674     return 0;
675 }
676
677 /* newCellNamep is required to be CELL_MAXNAMELEN in size */
678 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
679                         cm_configProc_t *procp, void *rockp)
680 {
681 #ifdef AFS_AFSDB_ENV
682     int rc;
683     int  cellHostAddrs[AFSMAXCELLHOSTS];
684     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
685     unsigned short ipRanks[AFSMAXCELLHOSTS];
686     int numServers;
687     int i;
688     struct sockaddr_in vlSockAddr;
689 #ifdef CELLSERV_DEBUG
690     osi_Log1(afsd_logp,"SearchCellDNS-Doing search for [%s]", osi_LogSaveString(afsd_logp,cellNamep));
691 #endif
692     if ( IsWindowsModule(cellNamep) )
693         return -1;
694     rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, ipRanks, &numServers, ttl);
695     if (rc == 0 && numServers > 0) {     /* found the cell */
696         for (i = 0; i < numServers; i++) {
697             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
698                    sizeof(long));
699             vlSockAddr.sin_family = AF_INET;
700             /* sin_port supplied by connection code */
701             if (procp)
702                 (*procp)(rockp, &vlSockAddr, cellHostNames[i], ipRanks[i]);
703         }
704         if (newCellNamep) {
705             strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
706             newCellNamep[CELL_MAXNAMELEN-1] = '\0';
707             strlwr(newCellNamep);
708         }
709         return 0;   /* found cell */
710     }
711     else
712        return -1;  /* not found */
713 #else
714     return -1;  /* not found */
715 #endif /* AFS_AFSDB_ENV */
716 }
717
718 /* use cm_GetConfigDir() plus AFS_CELLSERVDB to 
719  * generate the fully qualified name of the CellServDB 
720  * file.
721  */
722 long cm_GetCellServDB(char *cellNamep, afs_uint32 len)
723 {
724     size_t tlen;
725     
726     cm_GetConfigDir(cellNamep, len);
727
728     /* add trailing backslash, if required */
729     tlen = (int)strlen(cellNamep);
730     if (tlen) {
731         if (cellNamep[tlen-1] != '\\') {
732             strncat(cellNamep, "\\", len);
733             cellNamep[len-1] = '\0';
734         }
735         
736         strncat(cellNamep, AFS_CELLSERVDB, len);
737         cellNamep[len-1] = '\0';
738     }
739     return 0;
740 }
741
742 /* look up the root cell's name in the Registry 
743  * Input buffer must be at least CELL_MAXNAMELEN 
744  * in size.  (Defined in cm_cell.h)
745  */
746 long cm_GetRootCellName(char *cellNamep)
747 {
748     DWORD code, dummyLen;
749     HKEY parmKey;
750
751     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
752                         0, KEY_QUERY_VALUE, &parmKey);
753     if (code != ERROR_SUCCESS)
754         return -1;
755
756     dummyLen = CELL_MAXNAMELEN;
757     code = RegQueryValueEx(parmKey, "Cell", NULL, NULL,
758                                 cellNamep, &dummyLen);
759     RegCloseKey (parmKey);
760     if (code != ERROR_SUCCESS || cellNamep[0] == 0)
761         return -1;
762
763     return 0;
764 }
765
766 cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
767 {
768     char wdir[MAX_PATH]="";
769     FILE *tfilep = NULL;
770
771     cm_GetConfigDir(wdir, sizeof(wdir));
772     if (*wdir) {
773         strncat(wdir, namep, sizeof(wdir));
774         wdir[sizeof(wdir)-1] = '\0';
775         
776         tfilep = fopen(wdir, rwp);
777     }
778     return ((cm_configFile_t *) tfilep);        
779 }       
780
781 long cm_WriteConfigString(char *labelp, char *valuep)
782 {
783     DWORD code, dummyDisp;
784     HKEY parmKey;
785
786     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
787                            0, "container", 0, KEY_SET_VALUE, NULL,
788                            &parmKey, &dummyDisp);
789     if (code != ERROR_SUCCESS)
790         return -1;
791
792     code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
793                           valuep, (DWORD)strlen(valuep) + 1);
794     RegCloseKey (parmKey);
795     if (code != ERROR_SUCCESS)
796         return (long)-1;
797
798     return (long)0;
799 }
800
801 long cm_WriteConfigInt(char *labelp, long value)
802 {
803     DWORD code, dummyDisp;
804     HKEY parmKey;
805
806     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
807                            0, "container", 0, KEY_SET_VALUE, NULL,
808                            &parmKey, &dummyDisp);
809     if (code != ERROR_SUCCESS)
810         return -1;
811
812     code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
813                           (LPBYTE)&value, sizeof(value));
814     RegCloseKey (parmKey);
815     if (code != ERROR_SUCCESS)
816         return -1;
817
818     return 0;
819 }
820
821 cm_configFile_t *cm_OpenCellFile(void)
822 {
823     cm_configFile_t *cfp;
824
825     cfp = cm_CommonOpen(AFS_CELLSERVDB ".new", "w");
826     return cfp;
827 }
828
829 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
830 {
831     cm_configFile_t *tfilep;    /* input file */
832     char *tp;
833     char lineBuffer[256];
834     char *valuep;
835     int inRightCell;
836     int foundCell;
837
838     tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
839     if (!tfilep) 
840         return -1;
841
842     foundCell = 0;
843
844     /* have we seen the cell line for the guy we're looking for? */
845     inRightCell = 0;
846     while (1) {
847         tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
848         if (tp == NULL) {
849             if (feof((FILE *)tfilep)) {
850                 /* hit EOF */
851                 fclose((FILE *)tfilep);
852                 return 0;
853             }
854         }
855
856         /* turn trailing cr or lf into null */
857         tp = strchr(lineBuffer, '\r');
858         if (tp) *tp = 0;
859         tp = strchr(lineBuffer, '\n');
860         if (tp) *tp = 0;
861                 
862         /* skip blank lines */
863         if (lineBuffer[0] == 0) {
864             fprintf((FILE *)ofp, "%s\n", lineBuffer);
865             continue;
866         }
867
868         if (lineBuffer[0] == '>') {
869             /* trim off at white space or '#' chars */
870             tp = strchr(lineBuffer, ' ');
871             if (tp) *tp = 0;
872             tp = strchr(lineBuffer, '\t');
873             if (tp) *tp = 0;
874             tp = strchr(lineBuffer, '#');
875             if (tp) *tp = 0;
876
877             /* now see if this is the right cell */
878             if (strcmp(lineBuffer+1, cellNamep) == 0) {
879                 /* found the cell we're looking for */
880                 inRightCell = 1;
881             }
882             else {
883                 inRightCell = 0;
884                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
885             }
886         }
887         else {
888             valuep = strchr(lineBuffer, '#');
889             if (valuep == NULL) return -2;
890             valuep++;   /* skip the "#" */
891             if (!inRightCell) {
892                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
893             }
894         }       /* a vldb line */
895     }           /* while loop processing all lines */
896 }       
897
898 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
899 {
900     fprintf((FILE *)filep, ">%s\n", cellNamep);
901     return 0;
902 }
903
904 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
905 {
906     fprintf((FILE *)filep, "%s\n", linep);
907     return 0;
908 }
909
910 long cm_CloseCellFile(cm_configFile_t *filep)
911 {
912     char wdir[MAX_PATH];
913     char sdir[MAX_PATH];
914     long code;
915     long closeCode;
916     closeCode = fclose((FILE *)filep);
917
918     cm_GetConfigDir(wdir, sizeof(wdir));
919     strcpy(sdir, wdir);
920
921     if (closeCode != 0) {
922         /* something went wrong, preserve original database */
923         strncat(wdir, AFS_CELLSERVDB ".new", sizeof(wdir));
924         wdir[sizeof(wdir)-1] = '\0';
925         unlink(wdir);
926         return closeCode;
927     }
928
929     strncat(wdir, AFS_CELLSERVDB, sizeof(wdir));
930     wdir[sizeof(wdir)-1] = '\0';
931     strncat(sdir, AFS_CELLSERVDB ".new", sizeof(sdir));/* new file */
932     sdir[sizeof(sdir)-1] = '\0';
933
934     unlink(sdir);                       /* delete old file */
935
936     code = rename(sdir, wdir);  /* do the rename */
937
938     if (code) 
939         code = errno;
940
941     return code;
942 }   
943
944 void cm_GetConfigDir(char *dir, afs_uint32 len)
945 {
946     char * dirp = NULL;
947
948     if (!afssw_GetClientCellServDBDir(&dirp)) {
949         strncpy(dir, dirp, len);
950         dir[len-1] = '\0';
951         free(dirp);
952     } else {
953         dir[0] = '\0';
954     }
955 }