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