7f2a1142226ff595d2e6df53c9da434fef0adbc6
[openafs.git] / src / budb / server.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 #ifdef AFS_NT40_ENV
12 #include <winsock2.h>
13 #include <fcntl.h>
14 #include <WINNT/afsevent.h>
15 #else
16 #include <netinet/in.h>
17 #include <sys/file.h>
18 #include <sys/time.h>
19 #include <netdb.h>
20 #endif
21 #include <afs/stds.h>
22 #include <sys/types.h>
23 #include <time.h>
24 #include <stdio.h>
25 #include <afs/cmd.h>
26 #include <lwp.h>
27 #include <ubik.h>
28 #include <rx/xdr.h>
29 #include <rx/rx.h>
30 #include <rx/rxkad.h>
31 #include <rx/rx_globals.h>
32 #include <afs/cellconfig.h>
33 #include <afs/auth.h>
34 #include <afs/bubasics.h>
35 #include <afs/afsutil.h>
36 #include <afs/com_err.h>
37 #include <errno.h>
38 #ifdef  AFS_AIX32_ENV
39 #include <signal.h>
40 #endif
41 #include "budb_errs.h"
42 #include "database.h"
43 #include "error_macros.h"
44 #include "globals.h"
45 #include "afs/audit.h"
46
47
48 extern afs_int32 ubik_lastYesTime;
49 extern afs_int32 ubik_nBuffers;
50
51 struct ubik_dbase       *BU_dbase;
52 struct afsconf_dir      *BU_conf;       /* for getting cell info */
53
54 char lcell[MAXKTCREALMLEN];
55 afs_int32 myHost = 0;
56 int  helpOption;
57
58 /* server's global configuration information. This is exported to other
59  * files/routines
60  */
61
62 buServerConfT   globalConf;
63 buServerConfP   globalConfPtr = &globalConf;
64 char dbDir[AFSDIR_PATH_MAX], cellConfDir[AFSDIR_PATH_MAX];
65 /* debugging control */
66 int debugging = 0;
67
68 /* check whether caller is authorized to manage RX statistics */
69 int BU_rxstat_userok(call)
70     struct rx_call *call;
71 {
72     return afsconf_SuperUser(BU_conf, call, (char *)0);
73 }
74
75 int
76 convert_cell_to_ubik (cellinfo, myHost, serverList)
77      struct afsconf_cell *cellinfo;
78      afs_int32                *myHost;
79      afs_int32                *serverList;
80 {   
81     int  i;
82     char hostname[64];
83     struct hostent *th;
84
85     /* get this host */
86     gethostname(hostname,sizeof(hostname));
87     th = gethostbyname(hostname);
88     if (!th)
89     {
90         printf("prserver: couldn't get address of this host.\n");
91         BUDB_EXIT(1);
92     }
93     bcopy(th->h_addr,myHost,sizeof(afs_int32));
94
95     for (i=0; i<cellinfo->numServers; i++)
96         /* omit my host from serverList */
97         if (cellinfo->hostAddr[i].sin_addr.s_addr != *myHost) 
98             *serverList++ = cellinfo->hostAddr[i].sin_addr.s_addr;
99
100     *serverList = 0;                    /* terminate list */
101     return 0;
102 }
103
104 /* MyBeforeProc
105  *      The whole purpose of MyBeforeProc is to detect
106  *      if the -help option was not within the command line.
107  *      If it were, this routine would never have been called.
108  */
109 static int MyBeforeProc(as)
110    register struct cmd_syndesc *as;
111 {
112    helpOption = 0;
113    return 0;
114 }
115
116 /* initializeCommands
117  *      initialize all the supported commands and their arguments
118  */
119
120 initializeArgHandler()
121 {
122     struct cmd_syndesc *cptr;
123
124     int argHandler();
125
126     cmd_SetBeforeProc(MyBeforeProc, (char *)0);
127
128     cptr = cmd_CreateSyntax((char *) 0, argHandler, (char *) 0,
129                             "Backup database server");
130
131     cmd_AddParm(cptr, "-database", CMD_SINGLE, CMD_OPTIONAL,
132                 "database directory");
133
134     cmd_AddParm(cptr, "-cellservdb", CMD_SINGLE, CMD_OPTIONAL,
135                 "cell configuration directory");
136
137     cmd_AddParm(cptr, "-resetdb", CMD_FLAG, CMD_OPTIONAL,
138                 "truncate the database");
139
140     cmd_AddParm(cptr, "-noauth", CMD_FLAG, CMD_OPTIONAL,
141                 "run without authentication");
142
143     cmd_AddParm(cptr, "-smallht", CMD_FLAG, CMD_OPTIONAL,
144                 "use small hash tables");
145
146     cmd_AddParm(cptr, "-servers", CMD_LIST, CMD_OPTIONAL,
147                 "list of ubik database servers");
148 }
149
150 int
151 argHandler(as, arock)
152      struct cmd_syndesc *as;
153      char *arock;
154 {
155
156     /* globalConfPtr provides the handle for the configuration information */
157
158     /* database directory */
159     if ( as->parms[0].items != 0 )
160     {
161         globalConfPtr->databaseDirectory = 
162                         (char *) malloc(strlen(as->parms[0].items->data)+1);
163         if ( globalConfPtr->databaseDirectory == 0 )
164             BUDB_EXIT(-1);
165         strcpy(globalConfPtr->databaseDirectory, as->parms[0].items->data);
166     }
167
168     /* -cellservdb, cell configuration directory */
169     if ( as->parms[1].items != 0 )
170     {
171         globalConfPtr->cellConfigdir = 
172                         (char *) malloc(strlen(as->parms[1].items->data)+1);
173         if ( globalConfPtr->cellConfigdir == 0 )
174             BUDB_EXIT(-1);
175
176         strcpy(globalConfPtr->cellConfigdir, as->parms[1].items->data);
177
178         globalConfPtr->debugFlags |= DF_RECHECKNOAUTH;
179     }
180
181     /* truncate the database */
182     if ( as->parms[2].items != 0 )
183         truncateDatabase();
184
185     /* run without authentication */
186     if ( as->parms[3].items != 0 )
187         globalConfPtr->debugFlags |= DF_NOAUTH;
188
189     /* use small hash tables */
190     if ( as->parms[4].items != 0 )
191         globalConfPtr->debugFlags |= DF_SMALLHT;
192
193     /* user provided list of ubik database servers */
194     if ( as->parms[5].items != 0 )
195         parseServerList(as->parms[5].items);
196
197     return 0;
198 }
199
200 /* --- */
201
202 parseServerList(itemPtr)
203      struct cmd_item *itemPtr;
204 {
205     struct cmd_item *save;
206     char **serverArgs;
207     char **ptr;
208     afs_int32 nservers = 0;
209     afs_int32 code = 0;
210
211     save = itemPtr;
212
213     /* compute number of servers in the list */
214     while ( itemPtr )
215     {
216         nservers++;
217         itemPtr = itemPtr->next;
218     }
219
220     LogDebug(3, "%d servers\n", nservers);
221     
222     /* now can allocate the space for the server arguments */
223     serverArgs = (char **) malloc( (nservers+2) * sizeof(char *) );
224     if ( serverArgs == 0 )
225         ERROR(-1);
226
227     ptr = serverArgs;
228     *ptr++ = "";
229     *ptr++ = "-servers";
230
231     /* now go through and construct the list of servers */
232     itemPtr = save;
233     while ( itemPtr )
234     {
235         *ptr++ = itemPtr->data;
236         itemPtr = itemPtr->next;
237     }
238
239     code = ubik_ParseServerList(nservers+2, serverArgs,
240                                 &globalConfPtr->myHost,
241                                 globalConfPtr->serverList);
242     if ( code )
243         ERROR(code);
244  
245     /* free space for the server args */
246     free( (char *) serverArgs);
247     
248 error_exit:
249     return(code);
250 }
251
252 /* truncateDatabase
253  *      truncates just the database file.
254  */
255
256 truncateDatabase()
257 {
258     char *path;
259     afs_int32 code = 0;
260     int fd;
261
262     path = (char *) malloc(strlen(globalConfPtr->databaseDirectory) +
263                            strlen(globalConfPtr->databaseName) +
264                            strlen(globalConfPtr->databaseExtension) + 1);
265     if ( path == 0 )
266         ERROR(-1);
267
268     /* construct the database name */
269     strcpy(path, globalConfPtr->databaseDirectory);
270     strcat(path, globalConfPtr->databaseName);
271     strcat(path, globalConfPtr->databaseExtension);
272
273     fd = open(path, O_RDWR, 0755);
274     if (!fd) {
275         code = errno;
276     } else {
277         if (ftruncate(fd, 0) != 0 ) {
278             code = errno;
279         } else
280             close(fd);
281     }
282
283 error_exit:
284     return(code);
285 }
286
287
288 /* --- */
289
290 #include "AFS_component_version_number.c"
291
292 main(argc, argv)
293      int   argc;
294      char *argv[];
295 {
296     char *whoami = argv[0];
297     char *dbNamePtr = 0;
298     struct afsconf_cell  cellinfo;
299     time_t  currentTime;
300     afs_int32  code = 0;
301
302     struct rx_service *tservice;
303     struct rx_securityClass *sca[3];
304     
305     extern int afsconf_ClientAuth();
306     extern int afsconf_ServerAuth();
307     extern int afsconf_CheckAuth();
308
309     extern int rx_stackSize;
310     extern struct rx_securityClass *rxnull_NewServerSecurityObject();
311     extern int BUDB_ExecuteRequest();
312     extern afsconf_GetKey();
313     
314 #ifdef AFS_NT40_ENV
315     /* initialize winsock */
316     if (afs_winsockInit()<0) {
317       ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0],0);
318       fprintf(stderr, "%s: Couldn't initialize winsock.\n", whoami);
319       exit(1);
320     }
321 #endif
322
323 #ifdef  AFS_AIX32_ENV
324     /*
325      * The following signal action for AIX is necessary so that in case of a 
326      * crash (i.e. core is generated) we can include the user's data section 
327      * in the core dump. Unfortunately, by default, only a partial core is
328      * generated which, in many cases, isn't too useful.
329      */
330     struct sigaction nsa;
331     
332     sigemptyset(&nsa.sa_mask);
333     nsa.sa_handler = SIG_DFL;
334     nsa.sa_flags = SA_FULLDUMP;
335     sigaction(SIGSEGV, &nsa, NULL);
336     sigaction(SIGABRT, &nsa, NULL);
337 #endif
338     osi_audit(BUDB_StartEvent, 0, AUD_END);
339
340     initialize_budb_error_table();
341     initializeArgHandler();
342
343     /* Initialize dirpaths */
344     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
345 #ifdef AFS_NT40_ENV
346         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
347 #endif
348         com_err(whoami,errno,"; Unable to obtain AFS server directory.");
349         exit(2);
350     }
351
352     bzero(globalConfPtr, sizeof(*globalConfPtr));
353
354     /* set default configuration values */
355     strcpy(dbDir, AFSDIR_SERVER_DB_DIRPATH);
356     strcat(dbDir, "/");
357     globalConfPtr->databaseDirectory = dbDir;
358     globalConfPtr->databaseName = DEFAULT_DBPREFIX;
359     strcpy(cellConfDir, AFSDIR_SERVER_ETC_DIRPATH);
360     globalConfPtr->cellConfigdir = cellConfDir;
361
362     /* open the log file */
363 /*
364     globalConfPtr->log = fopen(DEFAULT_LOGNAME,"a");
365     if ( globalConfPtr->log == NULL )
366     {   
367         printf("Can't open log file %s - aborting\n", DEFAULT_LOGNAME);
368         BUDB_EXIT(-1);
369     }
370 */
371     
372     srandom (1);
373
374     /* process the user supplied args */
375     helpOption = 1;
376     code = cmd_Dispatch(argc, argv);
377     if ( code )
378         ERROR(code);
379
380     /* exit if there was a help option */
381     if (helpOption)
382         BUDB_EXIT(0);
383
384     /* open the log file */
385     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
386     if ( globalConfPtr->log == NULL )
387     {
388         printf("Can't open log file %s - aborting\n", 
389                AFSDIR_SERVER_BUDBLOG_FILEPATH);
390         BUDB_EXIT(-1);
391     }
392
393         /* keep log closed so can remove it */
394
395         fclose(globalConfPtr->log);
396
397     /* open the cell's configuration directory */
398     LogDebug(4, "opening %s\n", globalConfPtr->cellConfigdir);
399
400     BU_conf = afsconf_Open(globalConfPtr->cellConfigdir);
401     if ( BU_conf == 0 )
402     {
403         LogError(code, "Failed getting cell info\n");
404         com_err(whoami, code, "Failed getting cell info");
405         ERROR(BUDB_NOCELLS);
406     }
407
408     code = afsconf_GetLocalCell(BU_conf, lcell, sizeof(lcell));
409     if ( code )
410     {
411         LogError(0, "** Can't determine local cell name!\n");
412         ERROR(code);
413     }
414
415     if ( globalConfPtr->myHost == 0 )
416     {
417         /* if user hasn't supplied a list of servers, extract server
418          * list from the cell's database
419          */
420
421         LogDebug(1, "Using server list from %s cell database.\n", lcell);
422
423         code = afsconf_GetCellInfo (BU_conf, lcell, 0, &cellinfo);
424         code = convert_cell_to_ubik (&cellinfo, 
425                                      &globalConfPtr->myHost,
426                                      globalConfPtr->serverList);
427         if ( code )
428             ERROR(code);
429     }
430
431     /* initialize ubik */
432     ubik_CRXSecurityProc = afsconf_ClientAuth;
433     ubik_CRXSecurityRock = (char *)BU_conf;
434
435     ubik_SRXSecurityProc = afsconf_ServerAuth;
436     ubik_SRXSecurityRock = (char *)BU_conf;
437
438     ubik_CheckRXSecurityProc = afsconf_CheckAuth;
439     ubik_CheckRXSecurityRock = (char *)BU_conf;
440
441     ubik_nBuffers = 400;
442
443     dbNamePtr = (char *) malloc(strlen(globalConfPtr->databaseDirectory) +
444                            strlen(globalConfPtr->databaseName) + 1);
445     if ( dbNamePtr == 0 )
446         ERROR(-1);
447
448     /* construct the database name */
449     strcpy(dbNamePtr, globalConfPtr->databaseDirectory);
450     strcat(dbNamePtr, globalConfPtr->databaseName);     /* name prefix */
451
452     rx_SetRxDeadTime(60);                     /* 60 seconds inactive before timeout */
453
454     code = ubik_ServerInit(globalConfPtr->myHost,
455                            htons(AFSCONF_BUDBPORT), 
456                            globalConfPtr->serverList, 
457                            dbNamePtr,                   /* name prefix */
458                            &BU_dbase);
459     if (code)
460     {
461         LogError(code, "Ubik init failed\n");
462         com_err(whoami, code, "Ubik init failed");
463         ERROR(code);
464     }
465
466     sca[RX_SCINDEX_NULL] = rxnull_NewServerSecurityObject();
467     sca[RX_SCINDEX_VAB] = 0;
468     sca[RX_SCINDEX_KAD] = rxkad_NewServerSecurityObject(rxkad_clear,
469                                                           BU_conf,
470                                                           afsconf_GetKey,
471                                                           (char *) 0);
472
473     /* These two lines disallow jumbograms */
474     rx_maxReceiveSize = OLD_MAX_PACKET_SIZE;
475     rxi_nSendFrags = rxi_nRecvFrags = 1;
476
477     tservice = rx_NewService(0, BUDB_SERVICE, "BackupDatabase",
478                              sca, 3, BUDB_ExecuteRequest);
479     if (tservice == (struct rx_service *)0) 
480     {
481         LogError(0, "Could not create backup database rx service\n");
482         printf("Could not create backup database rx service\n");
483         BUDB_EXIT(3);
484     }
485     rx_SetMinProcs(tservice, 1);
486     rx_SetMaxProcs(tservice, 3);
487     rx_SetStackSize(tservice, 10000);
488
489     /* allow super users to manage RX statistics */
490     rx_SetRxStatUserOk(BU_rxstat_userok);
491
492     /* misc. initialization */
493
494     /* database dump synchronization */
495     bzero(dumpSyncPtr, sizeof(*dumpSyncPtr));
496     Lock_Init(&dumpSyncPtr->ds_lock);
497
498     rx_StartServer(0);                  /* start handling requests */
499
500     code = InitProcs();
501     if ( code )
502         ERROR(code);
503
504
505     currentTime = time(0);
506     LogError(0, "Ready to process requests at %s\n", ctime(&currentTime));
507
508     rx_ServerProc();                    /* donate this LWP */
509
510 error_exit:
511     osi_audit(BUDB_FinishEvent, code, AUD_END);
512     return(code);
513 }
514
515
516 consistencyCheckDb()
517 {
518     /* do consistency checks on structure sizes */
519     if ( (sizeof(struct htBlock) > BLOCKSIZE)
520     ||   (sizeof(struct vfBlock) > BLOCKSIZE)
521     ||   (sizeof(struct viBlock) > BLOCKSIZE)
522     ||   (sizeof(struct dBlock) > BLOCKSIZE)
523     ||   (sizeof(struct tBlock) > BLOCKSIZE) 
524        )
525     {
526         fprintf (stderr, "Block layout error!\n");
527         BUDB_EXIT (99);
528     }
529 }
530
531 /*VARARGS*/
532 LogDebug(level, a,b,c,d,e,f,g,h,i)
533     int level;
534     char *a, *b, *c, *d, *e, *f, *g, *h, *i;
535 {
536
537     if ( debugging >= level)
538     {
539         /* log normally closed so can remove it */
540         globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
541         if ( globalConfPtr->log != NULL )
542         {
543                 fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
544                 fflush(globalConfPtr->log);
545                 fclose(globalConfPtr->log);
546         }
547     }
548 }
549
550 static char *TimeStamp(time_t t)
551 {
552   struct tm *lt;
553   static char timestamp[20];
554
555   lt = localtime(&t);
556   strftime (timestamp, 20, "%m/%d/%Y %T", lt);
557   return timestamp;
558 }
559
560 /*VARARGS*/
561 Log(a,b,c,d,e,f,g,h,i)
562     char *a, *b, *c, *d, *e, *f, *g, *h, *i;
563 {
564     time_t now;
565
566     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
567     if ( globalConfPtr->log != NULL )
568     {
569         now = time(0);
570         fprintf(globalConfPtr->log, "%s ", TimeStamp(now));
571
572         fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
573         fflush(globalConfPtr->log);
574         fclose(globalConfPtr->log);
575     }
576 }
577
578 /*VARARGS*/
579 LogError(code, a,b,c,d,e,f,g,h,i)
580 long code;
581 char *a, *b, *c, *d, *e, *f, *g, *h, *i;
582 {
583     time_t now;
584
585     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
586
587     if ( globalConfPtr->log != NULL )
588     {
589         now = time(0);
590         fprintf(globalConfPtr->log, "%s ", TimeStamp(now));
591
592         if ( code )
593             fprintf(globalConfPtr->log, "%s: %s\n", error_table_name(code),
594                     error_message(code));
595         fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
596         fflush(globalConfPtr->log);
597         fclose(globalConfPtr->log);
598     }
599 }
600
601
602 /*  ----------------
603  * debug
604  * ----------------
605  */
606
607
608 LogNetDump(dumpPtr)
609      struct dump *dumpPtr;
610 {
611     struct dump hostDump;
612     extern buServerConfP globalConfPtr;
613     
614     dump_ntoh(dumpPtr, &hostDump);
615
616     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
617     if ( globalConfPtr->log != NULL )
618     {
619         printDump(globalConfPtr->log, &hostDump);
620         fclose(globalConfPtr->log);
621     }
622 }