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