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