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