DEVEL15-windows-search-cell-file-20080813
[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  * newCellNamep is required to be CELL_MAXNAMELEN in size.
116  */
117 long cm_SearchCellFile(char *cellNamep, char *newCellNamep,
118                        cm_configProc_t *procp, void *rockp)
119 {
120     char wdir[MAX_PATH]="";
121     FILE *tfilep = NULL, *bestp, *tempp;
122     char *tp;
123     char lineBuffer[257];
124     struct hostent *thp;
125     char *valuep;
126     struct sockaddr_in vlSockAddr;
127     int inRightCell = 0;
128     int foundCell = 0;
129     long code;
130     int tracking = 1, partial = 0;
131
132     if ( IsWindowsModule(cellNamep) )
133         return -3;
134
135     cm_GetCellServDB(wdir, sizeof(wdir));
136     if (*wdir)
137         tfilep = fopen(wdir, "r");
138
139     if (!tfilep) 
140         return -2;
141
142     bestp = fopen(wdir, "r");
143     
144 #ifdef CELLSERV_DEBUG
145     osi_Log2(afsd_logp,"cm_searchfile fopen handle[%p], wdir[%s]", bestp, 
146              osi_LogSaveString(afsd_logp,wdir));
147 #endif
148     /* have we seen the cell line for the guy we're looking for? */
149     while (1) {
150         tp = fgets(lineBuffer, sizeof(lineBuffer), tfilep);
151         if (tracking)
152             (void) fgets(lineBuffer, sizeof(lineBuffer), bestp);
153         if (tp == NULL) {
154             if (feof(tfilep)) {
155                 /* hit EOF */
156                 if (partial) {
157                     /*
158                      * found partial match earlier;
159                      * now go back to it
160                      */
161                     tempp = bestp;
162                     bestp = tfilep;
163                     tfilep = tempp;
164                     inRightCell = 1;
165                     partial = 0;
166                     continue;
167                 }
168                 else {
169                     fclose(tfilep);
170                     fclose(bestp);
171                     return (foundCell? 0 : -3);
172                 }
173             }
174         }       
175
176         /* turn trailing cr or lf into null */
177         tp = strrchr(lineBuffer, '\r');
178         if (tp) *tp = 0;
179         tp = strrchr(lineBuffer, '\n');
180         if (tp) *tp = 0;
181
182         /* skip blank lines */
183         if (lineBuffer[0] == 0) continue;
184
185         if (lineBuffer[0] == '>') {
186             if (inRightCell) {
187                 fclose(tfilep);
188                 fclose(bestp);
189                 return(foundCell ? 0 : -6);
190             }
191
192             /* trim off at white space or '#' chars */
193             tp = strchr(lineBuffer, ' ');
194             if (tp) *tp = 0;
195             tp = strchr(lineBuffer, '\t');
196             if (tp) *tp = 0;
197             tp = strchr(lineBuffer, '#');
198             if (tp) *tp = 0;
199
200             /* now see if this is the right cell */
201             if (stricmp(lineBuffer+1, cellNamep) == 0) {
202                 /* found the cell we're looking for */
203                 if (newCellNamep) {
204                     strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
205                     newCellNamep[CELL_MAXNAMELEN-1] = '\0';
206                     strlwr(newCellNamep);
207                 }
208                 inRightCell = 1;
209                 tracking = 0;
210 #ifdef CELLSERV_DEBUG                
211                 osi_Log2(afsd_logp, "cm_searchfile is cell inRightCell[%p], linebuffer[%s]",
212                          inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
213 #endif
214             }
215             else if (cm_stricmp_utf8(lineBuffer+1, cellNamep) == 0) {
216                 /* partial match */
217                 if (partial) {  /* ambiguous */
218                     fclose(tfilep);
219                     fclose(bestp);
220                     return -5;
221                 }
222                 if (newCellNamep) {
223                     strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
224                     newCellNamep[CELL_MAXNAMELEN-1] = '\0';
225                     strlwr(newCellNamep);
226                 }
227                 inRightCell = 0;
228                 tracking = 0;
229                 partial = 1;
230             }
231             else inRightCell = 0;
232         }
233         else {
234             valuep = strchr(lineBuffer, '#');
235             if (valuep == NULL) {
236                 fclose(tfilep);
237                 fclose(bestp);
238                 return -4;
239             }
240             valuep++;   /* skip the "#" */
241
242             valuep += strspn(valuep, " \t"); /* skip SP & TAB */
243             /* strip spaces and tabs in the end. They should not be there according to CellServDB format
244              * so do this just in case                        
245              */
246             while (valuep[strlen(valuep) - 1] == ' ' || valuep[strlen(valuep) - 1] == '\t') 
247                 valuep[strlen(valuep) - 1] = '\0';
248
249             if (inRightCell) {
250                 /* add the server to the VLDB list */
251                 WSASetLastError(0);
252                 thp = gethostbyname(valuep);
253 #ifdef CELLSERV_DEBUG
254                 osi_Log3(afsd_logp,"cm_searchfile inRightCell thp[%p], valuep[%s], WSAGetLastError[%d]",
255                          thp, osi_LogSaveString(afsd_logp,valuep), WSAGetLastError());
256 #endif
257                 if (thp) {
258                     memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr,
259                             sizeof(long));
260                     vlSockAddr.sin_family = AF_INET;
261                     /* sin_port supplied by connection code */
262                     if (procp)
263                         (*procp)(rockp, &vlSockAddr, valuep);
264                     foundCell = 1;
265                 }
266                 if (!thp) {
267                     afs_uint32 ip_addr;
268                     int c1, c2, c3, c4;
269                     
270                     /* Since there is no gethostbyname() data 
271                      * available we will read the IP address
272                      * stored in the CellServDB file
273                      */
274                     code = sscanf(lineBuffer, " %d.%d.%d.%d",
275                                    &c1, &c2, &c3, &c4);
276                     if (code == 4) {
277                         tp = (char *) &ip_addr;
278                         *tp++ = c1;
279                         *tp++ = c2;
280                         *tp++ = c3;
281                         *tp++ = c4;
282                         memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
283                                 sizeof(long));
284                         vlSockAddr.sin_family = AF_INET;
285                         /* sin_port supplied by connection code */
286                         if (procp)
287                             (*procp)(rockp, &vlSockAddr, valuep);
288                         foundCell = 1;
289                     }
290                 }
291             }
292         }       /* a vldb line */
293     }           /* while loop processing all lines */
294
295     /* if for some unknown reason cell is not found, return negative code (-11) ??? */
296     return (foundCell) ? 0 : -11;
297 }
298
299 /* newCellNamep is required to be CELL_MAXNAMELEN in size */
300 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
301                cm_configProc_t *procp, void *rockp)
302 {
303 #ifdef AFS_AFSDB_ENV
304     int rc;
305     int  cellHostAddrs[AFSMAXCELLHOSTS];
306     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
307     int numServers;
308     int i;
309     struct sockaddr_in vlSockAddr;
310 #ifdef CELLSERV_DEBUG
311     osi_Log1(afsd_logp,"SearchCellDNS-Doing search for [%s]", osi_LogSaveString(afsd_logp,cellNamep));
312 #endif
313     if ( IsWindowsModule(cellNamep) )
314         return -1;
315     rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, &numServers, ttl);
316     if (rc == 0 && numServers > 0) {     /* found the cell */
317         for (i = 0; i < numServers; i++) {
318             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
319                    sizeof(long));
320             vlSockAddr.sin_family = AF_INET;
321             /* sin_port supplied by connection code */
322             if (procp)
323                 (*procp)(rockp, &vlSockAddr, cellHostNames[i]);
324             if (newCellNamep) {
325                 strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
326                 newCellNamep[CELL_MAXNAMELEN-1] = '\0';
327                 strlwr(newCellNamep);
328             }
329         }
330         return 0;   /* found cell */
331     }
332     else
333        return -1;  /* not found */
334 #else
335     return -1;  /* not found */
336 #endif /* AFS_AFSDB_ENV */
337 }
338
339 /* use cm_GetConfigDir() plus AFS_CELLSERVDB to 
340  * generate the fully qualified name of the CellServDB 
341  * file.
342  */
343 long cm_GetCellServDB(char *cellNamep, afs_uint32 len)
344 {
345     size_t tlen;
346     
347     cm_GetConfigDir(cellNamep, len);
348
349     /* add trailing backslash, if required */
350     tlen = (int)strlen(cellNamep);
351     if (tlen) {
352         if (cellNamep[tlen-1] != '\\') {
353             strncat(cellNamep, "\\", len);
354             cellNamep[len-1] = '\0';
355         }
356         
357         strncat(cellNamep, AFS_CELLSERVDB, len);
358         cellNamep[len-1] = '\0';
359     }
360     return 0;
361 }
362
363 /* look up the root cell's name in the Registry */
364 long cm_GetRootCellName(char *cellNamep)
365 {
366     DWORD code, dummyLen;
367     HKEY parmKey;
368
369     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
370                         0, KEY_QUERY_VALUE, &parmKey);
371     if (code != ERROR_SUCCESS)
372         return -1;
373
374     dummyLen = 256;
375     code = RegQueryValueEx(parmKey, "Cell", NULL, NULL,
376                                 cellNamep, &dummyLen);
377     RegCloseKey (parmKey);
378     if (code != ERROR_SUCCESS || cellNamep[0] == 0)
379         return -1;
380
381     return 0;
382 }
383
384 cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
385 {
386     char wdir[MAX_PATH]="";
387     FILE *tfilep = NULL;
388
389     cm_GetConfigDir(wdir, sizeof(wdir));
390     if (*wdir) {
391         strncat(wdir, namep, sizeof(wdir));
392         wdir[sizeof(wdir)-1] = '\0';
393         
394         tfilep = fopen(wdir, rwp);
395     }
396     return ((cm_configFile_t *) tfilep);        
397 }       
398
399 long cm_WriteConfigString(char *labelp, char *valuep)
400 {
401     DWORD code, dummyDisp;
402     HKEY parmKey;
403
404     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
405                            0, "container", 0, KEY_SET_VALUE, NULL,
406                            &parmKey, &dummyDisp);
407     if (code != ERROR_SUCCESS)
408         return -1;
409
410     code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
411                           valuep, (DWORD)strlen(valuep) + 1);
412     RegCloseKey (parmKey);
413     if (code != ERROR_SUCCESS)
414         return (long)-1;
415
416     return (long)0;
417 }
418
419 long cm_WriteConfigInt(char *labelp, long value)
420 {
421     DWORD code, dummyDisp;
422     HKEY parmKey;
423
424     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
425                            0, "container", 0, KEY_SET_VALUE, NULL,
426                            &parmKey, &dummyDisp);
427     if (code != ERROR_SUCCESS)
428         return -1;
429
430     code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
431                           (LPBYTE)&value, sizeof(value));
432     RegCloseKey (parmKey);
433     if (code != ERROR_SUCCESS)
434         return -1;
435
436     return 0;
437 }
438
439 cm_configFile_t *cm_OpenCellFile(void)
440 {
441     cm_configFile_t *cfp;
442
443     cfp = cm_CommonOpen(AFS_CELLSERVDB ".new", "w");
444     return cfp;
445 }
446
447 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
448 {
449     cm_configFile_t *tfilep;    /* input file */
450     char *tp;
451     char lineBuffer[256];
452     char *valuep;
453     int inRightCell;
454     int foundCell;
455
456     tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
457     if (!tfilep) 
458         return -1;
459
460     foundCell = 0;
461
462     /* have we seen the cell line for the guy we're looking for? */
463     inRightCell = 0;
464     while (1) {
465         tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
466         if (tp == NULL) {
467             if (feof((FILE *)tfilep)) {
468                 /* hit EOF */
469                 fclose((FILE *)tfilep);
470                 return 0;
471             }
472         }
473
474         /* turn trailing cr or lf into null */
475         tp = strchr(lineBuffer, '\r');
476         if (tp) *tp = 0;
477         tp = strchr(lineBuffer, '\n');
478         if (tp) *tp = 0;
479                 
480         /* skip blank lines */
481         if (lineBuffer[0] == 0) {
482             fprintf((FILE *)ofp, "%s\n", lineBuffer);
483             continue;
484         }
485
486         if (lineBuffer[0] == '>') {
487             /* trim off at white space or '#' chars */
488             tp = strchr(lineBuffer, ' ');
489             if (tp) *tp = 0;
490             tp = strchr(lineBuffer, '\t');
491             if (tp) *tp = 0;
492             tp = strchr(lineBuffer, '#');
493             if (tp) *tp = 0;
494
495             /* now see if this is the right cell */
496             if (strcmp(lineBuffer+1, cellNamep) == 0) {
497                 /* found the cell we're looking for */
498                 inRightCell = 1;
499             }
500             else {
501                 inRightCell = 0;
502                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
503             }
504         }
505         else {
506             valuep = strchr(lineBuffer, '#');
507             if (valuep == NULL) return -2;
508             valuep++;   /* skip the "#" */
509             if (!inRightCell) {
510                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
511             }
512         }       /* a vldb line */
513     }           /* while loop processing all lines */
514 }       
515
516 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
517 {
518     fprintf((FILE *)filep, ">%s\n", cellNamep);
519     return 0;
520 }
521
522 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
523 {
524     fprintf((FILE *)filep, "%s\n", linep);
525     return 0;
526 }
527
528 long cm_CloseCellFile(cm_configFile_t *filep)
529 {
530     char wdir[MAX_PATH];
531     char sdir[MAX_PATH];
532     long code;
533     long closeCode;
534     closeCode = fclose((FILE *)filep);
535
536     cm_GetConfigDir(wdir, sizeof(wdir));
537     strcpy(sdir, wdir);
538
539     if (closeCode != 0) {
540         /* something went wrong, preserve original database */
541         strncat(wdir, AFS_CELLSERVDB ".new", sizeof(wdir));
542         wdir[sizeof(wdir)-1] = '\0';
543         unlink(wdir);
544         return closeCode;
545     }
546
547     strncat(wdir, AFS_CELLSERVDB, sizeof(wdir));
548     wdir[sizeof(wdir)-1] = '\0';
549     strncat(sdir, AFS_CELLSERVDB ".new", sizeof(sdir));/* new file */
550     sdir[sizeof(sdir)-1] = '\0';
551
552     unlink(sdir);                       /* delete old file */
553
554     code = rename(sdir, wdir);  /* do the rename */
555
556     if (code) 
557         code = errno;
558
559     return code;
560 }   
561
562 void cm_GetConfigDir(char *dir, afs_uint32 len)
563 {
564     char * dirp = NULL;
565
566     if (!afssw_GetClientCellServDBDir(&dirp)) {
567         strncpy(dir, dirp, len);
568         dir[len-1] = '\0';
569         free(dirp);
570     } else {
571         dir[0] = '\0';
572     }
573 }