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