windows-multi-fix-20061003
[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 <afs/param.h>
11 #include <afs/stds.h>
12 #include <afs/cellconfig.h>
13
14 #include <windows.h>
15 #include <winsock2.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "afsd.h"
21 #include <WINNT\afssw.h>
22 #include <WINNT\afsreg.h>
23 #ifdef AFS_AFSDB_ENV
24 #include "cm_dns.h"
25 #include <afs/afsint.h>
26 #endif
27
28 /* TODO: these should be pulled in from dirpath.h */
29 #define AFS_THISCELL "ThisCell"
30 #define AFS_CELLSERVDB_UNIX "CellServDB"
31 #define AFS_CELLSERVDB_NT "afsdcell.ini"
32 #ifndef AFSDIR_CLIENT_ETC_DIRPATH
33 #define AFSDIR_CLIENT_ETC_DIRPATH "c:/afs"
34 #endif
35 #define AFS_CELLSERVDB AFS_CELLSERVDB_UNIX
36
37 static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
38 {
39     char *tp;
40     char tc;
41     int sawEquals;
42     int sawBracket;
43         
44     sawEquals = 0;
45     sawBracket = 0;
46     for(tp = lineBufferp; *tp; tp++) {
47         tc = *tp;
48
49         if (sawBracket) {
50             if (tc == ']')
51                 sawBracket = 0;
52             continue;
53         }
54
55         /* comment or line end */
56         if (tc == '#' || tc == '\r' || tc == '\n') 
57             break;
58
59         /* square bracket comment -- look for closing delim */
60         if (tc == '[') {
61             sawBracket = 1; 
62             continue;
63         }       
64
65         /* space or tab */
66         if (tc == ' ' || tc == '\t') 
67             continue;
68
69         if (tc == '=') {
70             sawEquals = 1;
71             continue;
72         }
73
74         /* now we have a real character, put it in the appropriate bucket */
75         if (sawEquals == 0) {
76             *leftp++ = tc;
77         }       
78         else {  
79             *rightp++ = tc;
80         }
81     }
82
83     /* null terminate the strings */
84     *leftp = 0;
85     *rightp = 0;
86
87     return 0;   /* and return success */
88 }
89
90 static int
91 IsWindowsModule(const char * name)
92 {
93     const char * p;
94     int i;
95
96     /* Do not perform searches for probable Windows modules */
97     for (p = name, i=0; *p; p++) {
98         if ( *p == '.' )
99             i++;
100     }
101     p = strrchr(name, '.');
102     if (p) {
103         if (i == 1 && 
104             (!stricmp(p,".dll") ||
105              !stricmp(p,".exe") ||
106              !stricmp(p,".ini") ||
107              !stricmp(p,".db") ||
108              !stricmp(p,".drv")))
109             return 1;
110     }
111     return 0;
112 }
113
114 /* search for a cell, and either return an error code if we don't find it,
115  * or return 0 if we do, in which case we also fill in the addresses in
116  * the cellp field.
117  *
118  * new feature:  we can handle abbreviations and are insensitive to case.
119  * If the caller wants the "real" cell name, it puts a non-null pointer in
120  * newCellNamep.  Anomaly:  if cellNamep is ambiguous, we may modify
121  * newCellNamep but return an error code.
122  */
123 long cm_SearchCellFile(char *cellNamep, char *newCellNamep,
124                        cm_configProc_t *procp, void *rockp)
125 {
126     char wdir[257];
127     FILE *tfilep = NULL, *bestp, *tempp;
128     char *tp;
129     char lineBuffer[257];
130     struct hostent *thp;
131     char *valuep;
132     struct sockaddr_in vlSockAddr;
133     int inRightCell;
134     int foundCell = 0;
135     long code;
136     int tracking = 1, partial = 0;
137
138     if ( IsWindowsModule(cellNamep) )
139         return -3;
140
141     cm_GetCellServDB(wdir);
142     tfilep = fopen(wdir, "r");
143
144     /* If we are NT or higher, we don't do DJGPP, So just fail */
145     if ( !tfilep )
146         return -2;
147
148     bestp = fopen(wdir, "r");
149     
150 #ifdef CELLSERV_DEBUG
151     osi_Log2(afsd_logp,"cm_searchfile fopen handle[%p], wdir[%s]", bestp, 
152              osi_LogSaveString(afsd_logp,wdir));
153 #endif
154     /* have we seen the cell line for the guy we're looking for? */
155     inRightCell = 0;
156     while (1) {
157         tp = fgets(lineBuffer, sizeof(lineBuffer), tfilep);
158         if (tracking)
159             (void) fgets(lineBuffer, sizeof(lineBuffer), bestp);
160         if (    tp == NULL) {
161             if (feof(tfilep)) {
162                 /* hit EOF */
163                 if (partial) {
164                     /*
165                      * found partial match earlier;
166                      * now go back to it
167                      */
168                     tempp = bestp;
169                     bestp = tfilep;
170                     tfilep = tempp;
171                     inRightCell = 1;
172                     partial = 0;
173                     continue;
174                 }
175                 else {
176                     fclose(tfilep);
177                     fclose(bestp);
178                     return (foundCell? 0 : -3);
179                 }
180             }
181         }       
182
183         /* turn trailing cr or lf into null */
184         tp = strchr(lineBuffer, '\r');
185         if (tp) *tp = 0;
186         tp = strchr(lineBuffer, '\n');
187         if (tp) *tp = 0;
188
189         /* skip blank lines */
190         if (lineBuffer[0] == 0) continue;
191
192         if (lineBuffer[0] == '>') {
193             /* trim off at white space or '#' chars */
194             tp = strchr(lineBuffer, ' ');
195             if (tp) *tp = 0;
196             tp = strchr(lineBuffer, '\t');
197             if (tp) *tp = 0;
198             tp = strchr(lineBuffer, '#');
199             if (tp) *tp = 0;
200
201             /* now see if this is the right cell */
202             if (stricmp(lineBuffer+1, cellNamep) == 0) {
203                 /* found the cell we're looking for */
204                 if (newCellNamep)
205                     strcpy(newCellNamep, lineBuffer+1);
206                 inRightCell = 1;
207                 tracking = 0;
208 #ifdef CELLSERV_DEBUG                
209                 osi_Log2(afsd_logp, "cm_searchfile is cell inRightCell[%p], linebuffer[%s]",
210                          inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
211 #endif
212             }
213             else if (strnicmp(lineBuffer+1, cellNamep,
214                                strlen(cellNamep)) == 0) {
215                 /* partial match */
216                 if (partial) {  /* ambiguous */
217                     fclose(tfilep);
218                     fclose(bestp);
219                     return -5;
220                 }
221                 if (newCellNamep)
222                     strcpy(newCellNamep, lineBuffer+1);
223                 inRightCell = 0;
224                 tracking = 0;
225                 partial = 1;
226             }
227             else inRightCell = 0;
228         }
229         else {
230             valuep = strchr(lineBuffer, '#');
231             if (valuep == NULL) {
232                 fclose(tfilep);
233                 fclose(bestp);
234                 return -4;
235             }
236             valuep++;   /* skip the "#" */
237
238             valuep += strspn(valuep, " \t"); /* skip SP & TAB */
239             /* strip spaces and tabs in the end. They should not be there according to CellServDB format
240              * so do this just in case                        
241              */
242             while (valuep[strlen(valuep) - 1] == ' ' || valuep[strlen(valuep) - 1] == '\t') 
243                 valuep[strlen(valuep) - 1] = '\0';
244
245             if (inRightCell) {
246                 /* add the server to the VLDB list */
247                 WSASetLastError(0);
248                 thp = gethostbyname(valuep);
249 #ifdef CELLSERV_DEBUG
250                 osi_Log3(afsd_logp,"cm_searchfile inRightCell thp[%p], valuep[%s], WSAGetLastError[%d]",
251                          thp, osi_LogSaveString(afsd_logp,valuep), WSAGetLastError());
252 #endif
253                 if (thp) {
254                     memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr,
255                             sizeof(long));
256                     vlSockAddr.sin_family = AF_INET;
257                     /* sin_port supplied by connection code */
258                     if (procp)
259                         (*procp)(rockp, &vlSockAddr, valuep);
260                     foundCell = 1;
261                 }
262                 if (!thp) {
263                     long ip_addr;
264                     int c1, c2, c3, c4;
265                     char aname[241] = "";                    
266                     
267                     /* Since there is no gethostbyname() data 
268                      * available we will read the IP address
269                      * stored in the CellServDB file
270                      */
271                     code = sscanf(lineBuffer, "%d.%d.%d.%d #%s",
272                                    &c1, &c2, &c3, &c4, aname);
273                     tp = (char *) &ip_addr;
274                     *tp++ = c1;
275                     *tp++ = c2;
276                     *tp++ = c3;
277                     *tp++ = c4;
278                     memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
279                             sizeof(long));
280                     vlSockAddr.sin_family = AF_INET;
281                     /* sin_port supplied by connection code */
282                     if (procp)
283                         (*procp)(rockp, &vlSockAddr, valuep);
284                     foundCell = 1;
285                 }
286             }
287         }       /* a vldb line */
288     }           /* while loop processing all lines */
289
290     /* if for some unknown reason cell is not found, return negative code (-11) ??? */
291     return (foundCell) ? 0 : -11;
292 }
293
294 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
295                cm_configProc_t *procp, void *rockp)
296 {
297 #ifdef AFS_AFSDB_ENV
298     int rc;
299     int  cellHostAddrs[AFSMAXCELLHOSTS];
300     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
301     int numServers;
302     int i;
303     struct sockaddr_in vlSockAddr;
304 #ifdef CELLSERV_DEBUG
305     osi_Log1(afsd_logp,"SearchCellDNS-Doing search for [%s]", osi_LogSaveString(afsd_logp,cellNamep));
306 #endif
307     if ( IsWindowsModule(cellNamep) )
308         return -1;
309     rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, &numServers, ttl);
310     if (rc == 0 && numServers > 0) {     /* found the cell */
311         for (i = 0; i < numServers; i++) {
312             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
313                    sizeof(long));
314            vlSockAddr.sin_family = AF_INET;
315            /* sin_port supplied by connection code */
316            if (procp)
317           (*procp)(rockp, &vlSockAddr, cellHostNames[i]);
318            if(newCellNamep)
319           strcpy(newCellNamep,cellNamep);
320         }
321         return 0;   /* found cell */
322     }
323     else
324        return -1;  /* not found */
325 #else
326     return -1;  /* not found */
327 #endif /* AFS_AFSDB_ENV */
328 }
329
330 /* look up the CellServDBDir's name in the Registry 
331  * or use the Client Dirpath value to produce a CellServDB 
332  * filename
333  */
334 long cm_GetCellServDB(char *cellNamep)
335 {
336         DWORD code, dummyLen;
337         HKEY parmKey;
338     int tlen;
339
340         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
341                                 0, KEY_QUERY_VALUE, &parmKey);
342         if (code != ERROR_SUCCESS)
343         goto dirpath;
344
345         dummyLen = 256;
346         code = RegQueryValueEx(parmKey, "CellServDBDir", NULL, NULL,
347                                 cellNamep, &dummyLen);
348         RegCloseKey (parmKey);
349
350   dirpath:
351         if (code != ERROR_SUCCESS || cellNamep[0] == 0)
352         strcpy(cellNamep, AFSDIR_CLIENT_ETC_DIRPATH);
353
354     /* add trailing backslash, if required */
355     tlen = (int)strlen(cellNamep);
356     if (cellNamep[tlen-1] != '\\') 
357         strcat(cellNamep, "\\");
358         
359     strcat(cellNamep, AFS_CELLSERVDB);
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[256];
387     long tlen;
388     FILE *tfilep;
389
390     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
391         
392     /* add trailing backslash, if required */
393     tlen = (long)(strlen(wdir));
394     if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
395
396     strcat(wdir, namep);
397         
398     tfilep = fopen(wdir, rwp);
399
400     return ((cm_configFile_t *) tfilep);        
401 }       
402
403 long cm_WriteConfigString(char *labelp, char *valuep)
404 {
405     DWORD code, dummyDisp;
406     HKEY parmKey;
407
408     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
409                            0, "container", 0, KEY_SET_VALUE, NULL,
410                            &parmKey, &dummyDisp);
411     if (code != ERROR_SUCCESS)
412         return -1;
413
414     code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
415                           valuep, (DWORD)strlen(valuep) + 1);
416     RegCloseKey (parmKey);
417     if (code != ERROR_SUCCESS)
418         return (long)-1;
419
420     return (long)0;
421 }
422
423 long cm_WriteConfigInt(char *labelp, long value)
424 {
425         DWORD code, dummyDisp;
426         HKEY parmKey;
427
428         code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
429                                 0, "container", 0, KEY_SET_VALUE, NULL,
430                                 &parmKey, &dummyDisp);
431         if (code != ERROR_SUCCESS)
432                 return -1;
433
434         code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
435                              (LPBYTE)&value, sizeof(value));
436         RegCloseKey (parmKey);
437         if (code != ERROR_SUCCESS)
438                 return -1;
439
440         return 0;
441 }
442
443 cm_configFile_t *cm_OpenCellFile(void)
444 {
445         cm_configFile_t *cfp;
446
447         cfp = cm_CommonOpen("afsdcel2.ini", "w");
448         return cfp;
449 }
450
451 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
452 {
453         cm_configFile_t *tfilep;        /* input file */
454         char *tp;
455         char lineBuffer[256];
456         char *valuep;
457         int inRightCell;
458         int foundCell;
459
460         tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
461         if (!tfilep) return -1;
462
463         foundCell = 0;
464
465         /* have we seen the cell line for the guy we're looking for? */
466         inRightCell = 0;
467         while (1) {
468                 tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
469                 if (tp == NULL) {
470                         if (feof((FILE *)tfilep)) {
471                                 /* hit EOF */
472                                 fclose((FILE *)tfilep);
473                                 return 0;
474                         }
475                 }
476                 
477                 /* turn trailing cr or lf into null */
478                 tp = strchr(lineBuffer, '\r');
479                 if (tp) *tp = 0;
480                 tp = strchr(lineBuffer, '\n');
481                 if (tp) *tp = 0;
482                 
483                 /* skip blank lines */
484                 if (lineBuffer[0] == 0) {
485                         fprintf((FILE *)ofp, "%s\n", lineBuffer);
486                         continue;
487                 }
488
489                 if (lineBuffer[0] == '>') {
490                         /* trim off at white space or '#' chars */
491                         tp = strchr(lineBuffer, ' ');
492                         if (tp) *tp = 0;
493                         tp = strchr(lineBuffer, '\t');
494                         if (tp) *tp = 0;
495                         tp = strchr(lineBuffer, '#');
496                         if (tp) *tp = 0;
497
498                         /* now see if this is the right cell */
499                         if (strcmp(lineBuffer+1, cellNamep) == 0) {
500                                 /* found the cell we're looking for */
501                                 inRightCell = 1;
502                         }
503                         else {
504                                 inRightCell = 0;
505                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
506                         }
507                 }
508                 else {
509                         valuep = strchr(lineBuffer, '#');
510                         if (valuep == NULL) return -2;
511                         valuep++;       /* skip the "#" */
512                         if (!inRightCell) {
513                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
514                         }
515                 }       /* a vldb line */
516         }               /* while loop processing all lines */
517 }
518
519 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
520 {
521         fprintf((FILE *)filep, ">%s\n", cellNamep);
522         return 0;
523 }
524
525 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
526 {
527         fprintf((FILE *)filep, "%s\n", linep);
528         return 0;
529 }
530
531 long cm_CloseCellFile(cm_configFile_t *filep)
532 {
533     char wdir[256];
534     char sdir[256];
535     long code;
536     long closeCode;
537     int tlen;
538     closeCode = fclose((FILE *)filep);
539
540     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
541         
542         /* add trailing backslash, if required */
543     tlen = (int)strlen(wdir);
544     if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
545
546     strcpy(sdir, wdir);
547
548         if (closeCode != 0) {
549                 /* something went wrong, preserve original database */
550         strcat(wdir, "afsdcel2.ini");
551         unlink(wdir);
552         return closeCode;
553     }
554
555     strcat(wdir, AFS_CELLSERVDB);
556     strcat(sdir, "afsdcel2.ini");       /* new file */
557
558     unlink(wdir);                       /* delete old file */
559
560     code = rename(sdir, wdir);  /* do the rename */
561
562     if (code) 
563         code = errno;
564
565     return code;
566 }   
567
568 void cm_GetConfigDir(char *dir)
569 {
570         char wdir[256];
571     int tlen;
572 #ifdef AFS_WIN95_ENV
573     char *afsconf_path;
574     DWORD dwSize;
575 #endif
576
577     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
578         
579         /* add trailing backslash, if required */
580     tlen = (int)strlen(wdir);
581     if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
582     strcpy(dir, wdir);
583 }