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