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