Permit DNS SRV record lookups to be used by the Windows afsconf_GetAfsdbInfo
[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_port = htons(7003);
310                         vlSockAddr.sin_family = AF_INET;
311                         /* sin_port supplied by connection code */
312                         if (procp)
313                             (*procp)(rockp, &vlSockAddr, hostname, 0);
314                         foundAddr = 1;
315                     }
316                     /* if we didn't find a valid address, force the use of the specified one */
317                     if (!foundAddr)
318                         thp = NULL;
319                 }
320                 if (!thp) {
321                     afs_uint32 ip_addr;
322                     unsigned int c1, c2, c3, c4;
323                     
324                     /* Since there is no gethostbyname() data 
325                      * available we will read the IP address
326                      * stored in the CellServDB file
327                      */
328                     if (isClone)
329                         code = sscanf(lineBuffer, "[%u.%u.%u.%u]",
330                                       &c1, &c2, &c3, &c4);
331                     else
332                         code = sscanf(lineBuffer, " %u.%u.%u.%u",
333                                       &c1, &c2, &c3, &c4);
334                     if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
335                         tp = (unsigned char *) &ip_addr;
336                         *tp++ = c1;
337                         *tp++ = c2;
338                         *tp++ = c3;
339                         *tp++ = c4;
340                         memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
341                                 sizeof(long));
342                         vlSockAddr.sin_port = htons(7003);
343                         vlSockAddr.sin_family = AF_INET;
344                         /* sin_port supplied by connection code */
345                         if (procp)
346                             (*procp)(rockp, &vlSockAddr, hostname, 0);
347                     }
348                 }
349                 foundCell = 1;
350             }
351         }       /* a vldb line */
352     }           /* while loop processing all lines */
353
354     /* if for some unknown reason cell is not found, return negative code (-11) ??? */
355     return (foundCell) ? 0 : -11;
356 }
357
358 /*
359  * The CellServDB registry schema is as follows:
360  *
361  * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\
362  *   "LinkedCell"    REG_SZ "[cellname]" 
363  *   "Description"   REG_SZ "[comment]"
364  *   "ForceDNS"      DWORD  {0,1}
365  *
366  * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\[servername]\
367  *   "HostName"      REG_SZ "[hostname]" 
368  *   "IPv4Address"   REG_SZ "[address]" 
369  *   "IPv6Address"   REG_SZ "[address]"   <future>
370  *   "Comment"       REG_SZ "[comment]"
371  *   "Rank"          DWORD  "0..65535"
372  *   "Clone"         DWORD  "{0,1}"
373  *   "vlserver"      DWORD  "7003"        <future>
374  *   "ptserver"      DWORD  "7002"        <future>
375  *
376  * ForceDNS is implied non-zero if there are no [servername]
377  * keys under the [cellname] key.  Otherwise, ForceDNS is zero.
378  * If [servername] keys are specified and none of them evaluate
379  * to a valid server configuration, the return code is success.
380  * This prevents failover to the CellServDB file or DNS.
381  */
382 long cm_SearchCellRegistry(afs_uint32 client, 
383                            char *cellNamep, char *newCellNamep,
384                            char *linkedNamep,
385                            cm_configProc_t *procp, void *rockp)
386 {
387     HKEY hkCellServDB = 0, hkCellName = 0, hkServerName = 0;
388     DWORD dwType, dwSize;
389     DWORD dwCells, dwServers, dwForceDNS;
390     DWORD dwIndex, dwRank, dwPort;
391     unsigned short ipRank;
392     unsigned short vlPort;
393     LONG code;
394     FILETIME ftLastWriteTime;
395     char szCellName[CELL_MAXNAMELEN];
396     char szServerName[MAXHOSTCHARS];
397     char szHostName[MAXHOSTCHARS];
398     char szAddr[64];
399     struct hostent *thp;
400     struct sockaddr_in vlSockAddr;
401     char * s;
402
403     if ( IsWindowsModule(cellNamep) )
404         return -1;
405
406     /* No Server CellServDB list (yet) */
407     if ( !client )
408         return CM_ERROR_NOSUCHCELL;
409
410     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
411                       AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
412                       0,
413                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
414                       &hkCellServDB) != ERROR_SUCCESS)
415         return CM_ERROR_NOSUCHCELL;
416
417     if (RegOpenKeyEx( hkCellServDB, 
418                       cellNamep,
419                       0,
420                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
421                       &hkCellName) != ERROR_SUCCESS) {
422         BOOL bFound = 0;
423
424         /* We did not find an exact match.  Much search for partial matches. */
425
426         code = RegQueryInfoKey( hkCellServDB,
427                                 NULL,  /* lpClass */
428                                 NULL,  /* lpcClass */
429                                 NULL,  /* lpReserved */
430                                 &dwCells,  /* lpcSubKeys */
431                                 NULL,  /* lpcMaxSubKeyLen */
432                                 NULL,  /* lpcMaxClassLen */
433                                 NULL,  /* lpcValues */
434                                 NULL,  /* lpcMaxValueNameLen */
435                                 NULL,  /* lpcMaxValueLen */
436                                 NULL,  /* lpcbSecurityDescriptor */
437                                 &ftLastWriteTime /* lpftLastWriteTime */
438                                 );
439         if (code != ERROR_SUCCESS)
440             dwCells = 0;
441
442         /* 
443          * We search the entire list to ensure that there is only
444          * one prefix match.  If there is more than one, we return none.
445          */
446         for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
447             dwSize = CELL_MAXNAMELEN;
448             code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
449                                  NULL, NULL, &ftLastWriteTime);
450             if (code != ERROR_SUCCESS)
451                 continue;
452             szCellName[CELL_MAXNAMELEN-1] = '\0';
453             strlwr(szCellName);
454
455             /* if not a prefix match, try the next key */
456             if (strncmp(cellNamep, szCellName, strlen(cellNamep)))
457                 continue;
458
459             /* If we have a prefix match and we already found another
460              * match, return neither */
461             if (hkCellName) {
462                 bFound = 0;
463                 RegCloseKey( hkCellName);
464                 break;
465             }
466
467             if (RegOpenKeyEx( hkCellServDB, 
468                               szCellName,
469                               0,
470                               KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
471                               &hkCellName) != ERROR_SUCCESS)
472                 continue;
473
474             if (newCellNamep) {
475                 strncpy(newCellNamep, szCellName, CELL_MAXNAMELEN);
476                 newCellNamep[CELL_MAXNAMELEN-1] = '\0';
477             }
478             bFound = 1;
479         }
480
481         if ( !bFound ) {
482             RegCloseKey(hkCellServDB);
483             return CM_ERROR_NOSUCHCELL;
484         }
485     } else if (newCellNamep) {
486         strncpy(newCellNamep, cellNamep, CELL_MAXNAMELEN);
487         newCellNamep[CELL_MAXNAMELEN-1] = '\0';
488         strlwr(newCellNamep);
489     }
490
491     if (linkedNamep) {
492         dwSize = CELL_MAXNAMELEN;
493         code = RegQueryValueEx(hkCellName, "LinkedCell", NULL, &dwType,
494                                 (BYTE *) linkedNamep, &dwSize);
495         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
496             linkedNamep[CELL_MAXNAMELEN-1] = '\0';
497             strlwr(linkedNamep);
498         } else {
499             linkedNamep[0] = '\0';
500         }
501     }
502
503     /* Check to see if DNS lookups are required */
504     dwSize = sizeof(DWORD);
505     code = RegQueryValueEx(hkCellName, "ForceDNS", NULL, &dwType,
506                             (BYTE *) &dwForceDNS, &dwSize);
507     if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
508         if (dwForceDNS)
509             goto done;
510     } else {
511         dwForceDNS = 0;
512     }
513
514     /* 
515      * Using the defined server list.  Enumerate and populate
516      * the server list for the cell.
517      */
518     code = RegQueryInfoKey( hkCellName,
519                             NULL,  /* lpClass */
520                             NULL,  /* lpcClass */
521                             NULL,  /* lpReserved */
522                             &dwServers,  /* lpcSubKeys */
523                             NULL,  /* lpcMaxSubKeyLen */
524                             NULL,  /* lpcMaxClassLen */
525                             NULL,  /* lpcValues */
526                             NULL,  /* lpcMaxValueNameLen */
527                             NULL,  /* lpcMaxValueLen */
528                             NULL,  /* lpcbSecurityDescriptor */
529                             &ftLastWriteTime /* lpftLastWriteTime */
530                             );
531     if (code != ERROR_SUCCESS)
532         dwServers = 0;
533
534     for ( dwIndex = 0; dwIndex < dwServers; dwIndex++ ) {
535         dwSize = MAXHOSTCHARS;
536         code = RegEnumKeyEx( hkCellName, dwIndex, szServerName, &dwSize, NULL, 
537                              NULL, NULL, &ftLastWriteTime);
538         if (code != ERROR_SUCCESS)
539             continue;
540
541         szServerName[MAXHOSTCHARS-1] = '\0';
542         if (RegOpenKeyEx( hkCellName, 
543                           szServerName,
544                           0,
545                           KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
546                           &hkServerName) != ERROR_SUCCESS)
547             continue;
548
549         /* We have a handle to a valid server key.  Now we need 
550          * to add the server to the cell */
551         
552         /* First, see if there is an alternate hostname specified */
553         dwSize = MAXHOSTCHARS;
554         code = RegQueryValueEx(hkServerName, "HostName", NULL, &dwType,
555                                 (BYTE *) szHostName, &dwSize);
556         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
557             szHostName[MAXHOSTCHARS-1] = '\0';
558             strlwr(szHostName);
559             s = szHostName;
560         } else {
561             s = szServerName;
562         }
563
564         dwSize = sizeof(DWORD);
565         code = RegQueryValueEx(hkServerName, "Rank", NULL, &dwType,
566                                 (BYTE *) &dwRank, &dwSize);
567         if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
568             ipRank = (unsigned short)(dwRank <= 65535 ? dwRank : 65535);
569         } else {
570             ipRank = 0;
571         }
572
573         dwSize = sizeof(szAddr);
574         code = RegQueryValueEx(hkServerName, "IPv4Address", NULL, &dwType,
575                                 (BYTE *) szAddr, &dwSize);
576         if (code == ERROR_SUCCESS && dwType == REG_SZ) {
577             szAddr[63] = '\0';
578         } else {
579             szAddr[0] = '\0';
580         }
581
582         dwSize = sizeof(DWORD);
583         code = RegQueryValueEx(hkServerName, "vlserver", NULL, &dwType,
584                                 (BYTE *) &dwPort, &dwSize);
585         if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
586             vlPort = htons((unsigned short)dwPort);
587         } else {
588             vlPort = htons(7003);
589         }
590
591         WSASetLastError(0);
592         thp = gethostbyname(s);
593         if (thp) {
594             memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr, sizeof(long));
595             vlSockAddr.sin_port = htons(7003);
596             vlSockAddr.sin_family = AF_INET;
597             /* sin_port supplied by connection code */
598             if (procp)
599                 (*procp)(rockp, &vlSockAddr, s, ipRank);
600         } else if (szAddr[0]) {
601             afs_uint32 ip_addr;
602             unsigned int c1, c2, c3, c4;
603
604             /* Since there is no gethostbyname() data 
605              * available we will read the IP address
606              * stored in the CellServDB file
607              */
608             code = sscanf(szAddr, " %u.%u.%u.%u",
609                            &c1, &c2, &c3, &c4);
610             if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
611                 unsigned char * tp = (unsigned char *) &ip_addr;
612                 *tp++ = c1;
613                 *tp++ = c2;
614                 *tp++ = c3;
615                 *tp++ = c4;
616                 memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
617                         sizeof(long));
618                 vlSockAddr.sin_port = vlPort;
619                 vlSockAddr.sin_family = AF_INET;
620                 /* sin_port supplied by connection code */
621                 if (procp)
622                     (*procp)(rockp, &vlSockAddr, s, ipRank);
623             }
624         }
625
626         RegCloseKey( hkServerName);
627     }
628
629   done:
630     RegCloseKey(hkCellName);
631     RegCloseKey(hkCellServDB);
632
633     return ((dwForceDNS || dwServers == 0) ? CM_ERROR_FORCE_DNS_LOOKUP : 0);
634 }
635
636 long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *procp, void *rockp)
637 {
638     HKEY hkCellServDB = 0;
639     DWORD dwSize;
640     DWORD dwCells;
641     DWORD dwIndex;
642     LONG code;
643     FILETIME ftLastWriteTime;
644     char szCellName[CELL_MAXNAMELEN];
645
646     /* No server CellServDB in the registry. */
647     if (!client || procp == NULL)
648         return 0;
649
650     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
651                       AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
652                       0,
653                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
654                       &hkCellServDB) != ERROR_SUCCESS)
655         return 0;
656
657     code = RegQueryInfoKey( hkCellServDB,
658                             NULL,  /* lpClass */
659                             NULL,  /* lpcClass */
660                             NULL,  /* lpReserved */
661                             &dwCells,  /* lpcSubKeys */
662                             NULL,  /* lpcMaxSubKeyLen */
663                             NULL,  /* lpcMaxClassLen */
664                             NULL,  /* lpcValues */
665                             NULL,  /* lpcMaxValueNameLen */
666                             NULL,  /* lpcMaxValueLen */
667                             NULL,  /* lpcbSecurityDescriptor */
668                             &ftLastWriteTime /* lpftLastWriteTime */
669                             );
670     if (code != ERROR_SUCCESS)
671         dwCells = 0;
672
673     /* 
674      * Enumerate each Cell and 
675      */
676     for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
677         dwSize = CELL_MAXNAMELEN;
678         code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
679                              NULL, NULL, &ftLastWriteTime);
680         if (code != ERROR_SUCCESS)
681             continue;
682         szCellName[CELL_MAXNAMELEN-1] = '\0';
683         strlwr(szCellName);
684
685         (*procp)(rockp, szCellName);
686     }
687
688     RegCloseKey(hkCellServDB);
689     return 0;
690 }
691
692 /* newCellNamep is required to be CELL_MAXNAMELEN in size */
693 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
694                         cm_configProc_t *procp, void *rockp)
695 {
696 #ifdef AFS_AFSDB_ENV
697     int rc;
698     int  cellHostAddrs[AFSMAXCELLHOSTS];
699     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
700     unsigned short ipRanks[AFSMAXCELLHOSTS];
701     unsigned short ports[AFSMAXCELLHOSTS];
702     int numServers;
703     int i;
704     struct sockaddr_in vlSockAddr;
705 #ifdef CELLSERV_DEBUG
706     osi_Log1(afsd_logp,"SearchCellDNS-Doing search for [%s]", osi_LogSaveString(afsd_logp,cellNamep));
707 #endif
708     /*
709      * Do not perform a DNS lookup if the name is
710      * either a well-known Windows DLL or directory,
711      * or if the name does not contain a top-level
712      * domain, or if the file prefix is the afs pioctl
713      * file name.
714      */
715     if ( IsWindowsModule(cellNamep) ||
716          cm_FsStrChr(cellNamep, '.') == NULL ||
717          strncasecmp(cellNamep, CM_IOCTL_FILENAME_NOSLASH, strlen(CM_IOCTL_FILENAME_NOSLASH)) == 0)
718         return -1;
719
720     rc = getAFSServer("afs3-vlserver", "udp", cellNamep, 7003,
721                       cellHostAddrs, cellHostNames, ports, ipRanks, &numServers, ttl);
722     if (rc == 0 && numServers > 0) {     /* found the cell */
723         for (i = 0; i < numServers; i++) {
724             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
725                    sizeof(long));
726             vlSockAddr.sin_port = ports[i];
727             vlSockAddr.sin_family = AF_INET;
728             if (procp)
729                 (*procp)(rockp, &vlSockAddr, cellHostNames[i], ipRanks[i]);
730         }
731         if (newCellNamep) {
732             strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
733             newCellNamep[CELL_MAXNAMELEN-1] = '\0';
734             strlwr(newCellNamep);
735         }
736         return 0;   /* found cell */
737     }
738     else
739        return -1;  /* not found */
740 #else
741     return -1;  /* not found */
742 #endif /* AFS_AFSDB_ENV */
743 }
744
745 /* use cm_GetConfigDir() plus AFS_CELLSERVDB to 
746  * generate the fully qualified name of the CellServDB 
747  * file.
748  */
749 long cm_GetCellServDB(char *cellNamep, afs_uint32 len)
750 {
751     size_t tlen;
752     
753     cm_GetConfigDir(cellNamep, len);
754
755     /* add trailing backslash, if required */
756     tlen = (int)strlen(cellNamep);
757     if (tlen) {
758         if (cellNamep[tlen-1] != '\\') {
759             strncat(cellNamep, "\\", len);
760             cellNamep[len-1] = '\0';
761         }
762         
763         strncat(cellNamep, AFS_CELLSERVDB, len);
764         cellNamep[len-1] = '\0';
765     }
766     return 0;
767 }
768
769 /* look up the root cell's name in the Registry 
770  * Input buffer must be at least CELL_MAXNAMELEN 
771  * in size.  (Defined in cm_cell.h)
772  */
773 long cm_GetRootCellName(char *cellNamep)
774 {
775     DWORD code, dummyLen;
776     HKEY parmKey;
777
778     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
779                         0, KEY_QUERY_VALUE, &parmKey);
780     if (code != ERROR_SUCCESS)
781         return -1;
782
783     dummyLen = CELL_MAXNAMELEN;
784     code = RegQueryValueEx(parmKey, "Cell", NULL, NULL,
785                                 cellNamep, &dummyLen);
786     RegCloseKey (parmKey);
787     if (code != ERROR_SUCCESS || cellNamep[0] == 0)
788         return -1;
789
790     return 0;
791 }
792
793 cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
794 {
795     char wdir[MAX_PATH]="";
796     FILE *tfilep = NULL;
797
798     cm_GetConfigDir(wdir, sizeof(wdir));
799     if (*wdir) {
800         strncat(wdir, namep, sizeof(wdir));
801         wdir[sizeof(wdir)-1] = '\0';
802         
803         tfilep = fopen(wdir, rwp);
804     }
805     return ((cm_configFile_t *) tfilep);        
806 }       
807
808 long cm_WriteConfigString(char *labelp, char *valuep)
809 {
810     DWORD code, dummyDisp;
811     HKEY parmKey;
812
813     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
814                            0, "container", 0, KEY_SET_VALUE, NULL,
815                            &parmKey, &dummyDisp);
816     if (code != ERROR_SUCCESS)
817         return -1;
818
819     code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
820                           valuep, (DWORD)strlen(valuep) + 1);
821     RegCloseKey (parmKey);
822     if (code != ERROR_SUCCESS)
823         return (long)-1;
824
825     return (long)0;
826 }
827
828 long cm_WriteConfigInt(char *labelp, long value)
829 {
830     DWORD code, dummyDisp;
831     HKEY parmKey;
832
833     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
834                            0, "container", 0, KEY_SET_VALUE, NULL,
835                            &parmKey, &dummyDisp);
836     if (code != ERROR_SUCCESS)
837         return -1;
838
839     code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
840                           (LPBYTE)&value, sizeof(value));
841     RegCloseKey (parmKey);
842     if (code != ERROR_SUCCESS)
843         return -1;
844
845     return 0;
846 }
847
848 cm_configFile_t *cm_OpenCellFile(void)
849 {
850     cm_configFile_t *cfp;
851
852     cfp = cm_CommonOpen(AFS_CELLSERVDB ".new", "w");
853     return cfp;
854 }
855
856 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
857 {
858     cm_configFile_t *tfilep;    /* input file */
859     char *tp;
860     char lineBuffer[256];
861     char *valuep;
862     int inRightCell;
863     int foundCell;
864
865     tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
866     if (!tfilep) 
867         return -1;
868
869     foundCell = 0;
870
871     /* have we seen the cell line for the guy we're looking for? */
872     inRightCell = 0;
873     while (1) {
874         tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
875         if (tp == NULL) {
876             if (feof((FILE *)tfilep)) {
877                 /* hit EOF */
878                 fclose((FILE *)tfilep);
879                 return 0;
880             }
881         }
882
883         /* turn trailing cr or lf into null */
884         tp = strchr(lineBuffer, '\r');
885         if (tp) *tp = 0;
886         tp = strchr(lineBuffer, '\n');
887         if (tp) *tp = 0;
888                 
889         /* skip blank lines */
890         if (lineBuffer[0] == 0) {
891             fprintf((FILE *)ofp, "%s\n", lineBuffer);
892             continue;
893         }
894
895         if (lineBuffer[0] == '>') {
896             /* trim off at white space or '#' chars */
897             tp = strchr(lineBuffer, ' ');
898             if (tp) *tp = 0;
899             tp = strchr(lineBuffer, '\t');
900             if (tp) *tp = 0;
901             tp = strchr(lineBuffer, '#');
902             if (tp) *tp = 0;
903
904             /* now see if this is the right cell */
905             if (strcmp(lineBuffer+1, cellNamep) == 0) {
906                 /* found the cell we're looking for */
907                 inRightCell = 1;
908             }
909             else {
910                 inRightCell = 0;
911                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
912             }
913         }
914         else {
915             valuep = strchr(lineBuffer, '#');
916             if (valuep == NULL) return -2;
917             valuep++;   /* skip the "#" */
918             if (!inRightCell) {
919                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
920             }
921         }       /* a vldb line */
922     }           /* while loop processing all lines */
923 }       
924
925 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
926 {
927     fprintf((FILE *)filep, ">%s\n", cellNamep);
928     return 0;
929 }
930
931 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
932 {
933     fprintf((FILE *)filep, "%s\n", linep);
934     return 0;
935 }
936
937 long cm_CloseCellFile(cm_configFile_t *filep)
938 {
939     char wdir[MAX_PATH];
940     char sdir[MAX_PATH];
941     long code;
942     long closeCode;
943     closeCode = fclose((FILE *)filep);
944
945     cm_GetConfigDir(wdir, sizeof(wdir));
946     strcpy(sdir, wdir);
947
948     if (closeCode != 0) {
949         /* something went wrong, preserve original database */
950         strncat(wdir, AFS_CELLSERVDB ".new", sizeof(wdir));
951         wdir[sizeof(wdir)-1] = '\0';
952         unlink(wdir);
953         return closeCode;
954     }
955
956     strncat(wdir, AFS_CELLSERVDB, sizeof(wdir));
957     wdir[sizeof(wdir)-1] = '\0';
958     strncat(sdir, AFS_CELLSERVDB ".new", sizeof(sdir));/* new file */
959     sdir[sizeof(sdir)-1] = '\0';
960
961     unlink(sdir);                       /* delete old file */
962
963     code = rename(sdir, wdir);  /* do the rename */
964
965     if (code) 
966         code = errno;
967
968     return code;
969 }   
970
971 void cm_GetConfigDir(char *dir, afs_uint32 len)
972 {
973     char * dirp = NULL;
974
975     if (!afssw_GetClientCellServDBDir(&dirp)) {
976         strncpy(dir, dirp, len);
977         dir[len-1] = '\0';
978         free(dirp);
979     } else {
980         dir[0] = '\0';
981     }
982 }