lwp-protoize-20080310
[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 RCSID
14     ("$Header$");
15
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #ifdef AFS_NT40_ENV
19 #include <winsock2.h>
20 #include <WINNT/afsevent.h>
21 #else
22 #include <netinet/in.h>
23 #include <sys/file.h>
24 #include <sys/time.h>
25 #include <netdb.h>
26 #endif
27 #include <string.h>
28 #include <afs/stds.h>
29 #include <sys/types.h>
30 #include <time.h>
31 #include <stdio.h>
32 #include <afs/cmd.h>
33 #include <lwp.h>
34 #include <ubik.h>
35 #include <rx/xdr.h>
36 #include <rx/rx.h>
37 #include <rx/rxkad.h>
38 #include <rx/rx_globals.h>
39 #include <afs/cellconfig.h>
40 #include <afs/bubasics.h>
41 #include <afs/afsutil.h>
42 #include <afs/com_err.h>
43 #include <errno.h>
44 #ifdef  AFS_AIX32_ENV
45 #include <signal.h>
46 #endif
47 #include "budb_errs.h"
48 #include "database.h"
49 #include "error_macros.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
58 char lcell[MAXKTCREALMLEN];
59 afs_int32 myHost = 0;
60 int helpOption;
61
62 /* server's global configuration information. This is exported to other
63  * files/routines
64  */
65
66 buServerConfT globalConf;
67 buServerConfP globalConfPtr = &globalConf;
68 char dbDir[AFSDIR_PATH_MAX], cellConfDir[AFSDIR_PATH_MAX];
69 /* debugging control */
70 int debugging = 0;
71
72 int rxBind = 0;
73
74 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
75 afs_uint32 SHostAddrs[ADDRSPERSITE];
76
77 #if defined(AFS_PTHREAD_ENV)
78 char *
79 threadNum(void)
80 {
81     return pthread_getspecific(rx_thread_id_key);
82 }
83 #endif
84
85 /* check whether caller is authorized to manage RX statistics */
86 int
87 BU_rxstat_userok(call)
88      struct rx_call *call;
89 {
90     return afsconf_SuperUser(BU_conf, call, NULL);
91 }
92
93 int
94 convert_cell_to_ubik(cellinfo, myHost, serverList)
95      struct afsconf_cell *cellinfo;
96      afs_int32 *myHost;
97      afs_int32 *serverList;
98 {
99     int i;
100     char hostname[64];
101     struct hostent *th;
102
103     /* get this host */
104     gethostname(hostname, sizeof(hostname));
105     th = gethostbyname(hostname);
106     if (!th) {
107         printf("prserver: couldn't get address of this host.\n");
108         BUDB_EXIT(1);
109     }
110     memcpy(myHost, th->h_addr, sizeof(afs_int32));
111
112     for (i = 0; i < cellinfo->numServers; i++)
113         /* omit my host from serverList */
114         if (cellinfo->hostAddr[i].sin_addr.s_addr != *myHost)
115             *serverList++ = cellinfo->hostAddr[i].sin_addr.s_addr;
116
117     *serverList = 0;            /* terminate list */
118     return 0;
119 }
120
121 /* MyBeforeProc
122  *      The whole purpose of MyBeforeProc is to detect
123  *      if the -help option was not within the command line.
124  *      If it were, this routine would never have been called.
125  */
126 static int
127 MyBeforeProc(register struct cmd_syndesc *as, void *arock)
128 {
129     helpOption = 0;
130     return 0;
131 }
132
133 /* initializeCommands
134  *      initialize all the supported commands and their arguments
135  */
136
137 void
138 initializeArgHandler()
139 {
140     struct cmd_syndesc *cptr;
141
142     cmd_SetBeforeProc(MyBeforeProc, NULL);
143
144     cptr = cmd_CreateSyntax(NULL, argHandler, NULL, "Backup database server");
145
146     cmd_AddParm(cptr, "-database", CMD_SINGLE, CMD_OPTIONAL,
147                 "database directory");
148
149     cmd_AddParm(cptr, "-cellservdb", CMD_SINGLE, CMD_OPTIONAL,
150                 "cell configuration directory");
151
152     cmd_AddParm(cptr, "-resetdb", CMD_FLAG, CMD_OPTIONAL,
153                 "truncate the database");
154
155     cmd_AddParm(cptr, "-noauth", CMD_FLAG, CMD_OPTIONAL,
156                 "run without authentication");
157
158     cmd_AddParm(cptr, "-smallht", CMD_FLAG, CMD_OPTIONAL,
159                 "use small hash tables");
160
161     cmd_AddParm(cptr, "-servers", CMD_LIST, CMD_OPTIONAL,
162                 "list of ubik database servers");
163
164     cmd_AddParm(cptr, "-ubikbuffers", CMD_SINGLE, CMD_OPTIONAL,
165                 "the number of ubik buffers");
166
167     cmd_AddParm(cptr, "-auditlog", CMD_SINGLE, CMD_OPTIONAL,
168                 "audit log path");
169
170 }
171
172 int
173 argHandler(struct cmd_syndesc *as, void *arock)
174 {
175
176     /* globalConfPtr provides the handle for the configuration information */
177
178     /* database directory */
179     if (as->parms[0].items != 0) {
180         globalConfPtr->databaseDirectory =
181             (char *)malloc(strlen(as->parms[0].items->data) + 1);
182         if (globalConfPtr->databaseDirectory == 0)
183             BUDB_EXIT(-1);
184         strcpy(globalConfPtr->databaseDirectory, as->parms[0].items->data);
185     }
186
187     /* -cellservdb, cell configuration directory */
188     if (as->parms[1].items != 0) {
189         globalConfPtr->cellConfigdir =
190             (char *)malloc(strlen(as->parms[1].items->data) + 1);
191         if (globalConfPtr->cellConfigdir == 0)
192             BUDB_EXIT(-1);
193
194         strcpy(globalConfPtr->cellConfigdir, as->parms[1].items->data);
195
196         globalConfPtr->debugFlags |= DF_RECHECKNOAUTH;
197     }
198
199     /* truncate the database */
200     if (as->parms[2].items != 0)
201         truncateDatabase();
202
203     /* run without authentication */
204     if (as->parms[3].items != 0)
205         globalConfPtr->debugFlags |= DF_NOAUTH;
206
207     /* use small hash tables */
208     if (as->parms[4].items != 0)
209         globalConfPtr->debugFlags |= DF_SMALLHT;
210
211     /* user provided list of ubik database servers */
212     if (as->parms[5].items != 0)
213         parseServerList(as->parms[5].items);
214
215     /* user provided the number of ubik buffers    */
216     if (as->parms[6].items != 0)
217         ubik_nBuffers = atoi(as->parms[6].items->data);
218     else
219         ubik_nBuffers = 0;
220
221     if (as->parms[7].items != 0) {
222         int tempfd, flags;
223         FILE *auditout;
224         char oldName[MAXPATHLEN];
225         char *fileName = as->parms[7].items->data;
226 #ifndef AFS_NT40_ENV
227         struct stat statbuf;
228
229         if ((lstat(fileName, &statbuf) == 0) 
230             && (S_ISFIFO(statbuf.st_mode))) {
231             flags = O_WRONLY | O_NONBLOCK;
232         } else 
233 #endif
234         {
235             strcpy(oldName, fileName);
236             strcat(oldName, ".old");
237             renamefile(fileName, oldName);
238             flags = O_WRONLY | O_TRUNC | O_CREAT;
239         }
240         tempfd = open(fileName, flags, 0666);
241         if (tempfd > -1) {
242             auditout = fdopen(tempfd, "a");
243             if (auditout) {
244                 osi_audit_file(auditout);
245             } else
246                 printf("Warning: auditlog %s not writable, ignored.\n", fileName);
247         } else
248             printf("Warning: auditlog %s not writable, ignored.\n", fileName);
249     }
250
251     return 0;
252 }
253
254 /* --- */
255
256 parseServerList(itemPtr)
257      struct cmd_item *itemPtr;
258 {
259     struct cmd_item *save;
260     char **serverArgs;
261     char **ptr;
262     afs_int32 nservers = 0;
263     afs_int32 code = 0;
264
265     save = itemPtr;
266
267     /* compute number of servers in the list */
268     while (itemPtr) {
269         nservers++;
270         itemPtr = itemPtr->next;
271     }
272
273     LogDebug(3, "%d servers\n", nservers);
274
275     /* now can allocate the space for the server arguments */
276     serverArgs = (char **)malloc((nservers + 2) * sizeof(char *));
277     if (serverArgs == 0)
278         ERROR(-1);
279
280     ptr = serverArgs;
281     *ptr++ = "";
282     *ptr++ = "-servers";
283
284     /* now go through and construct the list of servers */
285     itemPtr = save;
286     while (itemPtr) {
287         *ptr++ = itemPtr->data;
288         itemPtr = itemPtr->next;
289     }
290
291     code =
292         ubik_ParseServerList(nservers + 2, serverArgs, &globalConfPtr->myHost,
293                              globalConfPtr->serverList);
294     if (code)
295         ERROR(code);
296
297     /* free space for the server args */
298     free((char *)serverArgs);
299
300   error_exit:
301     return (code);
302 }
303
304 /* truncateDatabase
305  *      truncates just the database file.
306  */
307
308 truncateDatabase()
309 {
310     char *path;
311     afs_int32 code = 0;
312     int fd;
313
314     path =
315         (char *)malloc(strlen(globalConfPtr->databaseDirectory) +
316                        strlen(globalConfPtr->databaseName) +
317                        strlen(globalConfPtr->databaseExtension) + 1);
318     if (path == 0)
319         ERROR(-1);
320
321     /* construct the database name */
322     strcpy(path, globalConfPtr->databaseDirectory);
323     strcat(path, globalConfPtr->databaseName);
324     strcat(path, globalConfPtr->databaseExtension);
325
326     fd = open(path, O_RDWR, 0755);
327     if (!fd) {
328         code = errno;
329     } else {
330         if (ftruncate(fd, 0) != 0) {
331             code = errno;
332         } else
333             close(fd);
334     }
335
336   error_exit:
337     return (code);
338 }
339
340
341 /* --- */
342
343 #include "AFS_component_version_number.c"
344
345 main(argc, argv)
346      int argc;
347      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 *sca[3];
360
361     extern int afsconf_ServerAuth();
362     extern int afsconf_CheckAuth();
363
364     extern int rx_stackSize;
365     extern int BUDB_ExecuteRequest();
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 = (char *)BU_conf;
489
490     ubik_SRXSecurityProc = afsconf_ServerAuth;
491     ubik_SRXSecurityRock = (char *)BU_conf;
492
493     ubik_CheckRXSecurityProc = afsconf_CheckAuth;
494     ubik_CheckRXSecurityRock = (char *)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 #ifndef AFS_NT40_ENV
516         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH || 
517             AFSDIR_SERVER_NETINFO_FILEPATH) {
518             char reason[1024];
519             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
520                                            ADDRSPERSITE, reason,
521                                            AFSDIR_SERVER_NETINFO_FILEPATH,
522                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
523         } else 
524 #endif  
525         {
526             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
527         }
528         if (ccode == 1) {
529             host = SHostAddrs[0];
530             rx_InitHost(host, htons(AFSCONF_BUDBPORT));
531         }
532     }
533
534     code = ubik_ServerInitByInfo (globalConfPtr->myHost,
535                                   htons(AFSCONF_BUDBPORT), 
536                                   &cellinfo,
537                                   &clones,              
538                                   dbNamePtr,           /* name prefix */
539                                   &BU_dbase);
540
541     if (code) {
542         LogError(code, "Ubik init failed\n");
543         afs_com_err(whoami, code, "Ubik init failed");
544         ERROR(code);
545     }
546
547     sca[RX_SCINDEX_NULL] = rxnull_NewServerSecurityObject();
548     sca[RX_SCINDEX_VAB] = 0;
549     sca[RX_SCINDEX_KAD] =
550         rxkad_NewServerSecurityObject(rxkad_clear, BU_conf, afsconf_GetKey,
551                                       NULL);
552
553     /* Disable jumbograms */
554     rx_SetNoJumbo();
555
556     tservice =
557         rx_NewServiceHost(host, 0, BUDB_SERVICE, "BackupDatabase", sca, 3,
558                       BUDB_ExecuteRequest);
559     if (tservice == (struct rx_service *)0) {
560         LogError(0, "Could not create backup database rx service\n");
561         printf("Could not create backup database rx service\n");
562         BUDB_EXIT(3);
563     }
564     rx_SetMinProcs(tservice, 1);
565     rx_SetMaxProcs(tservice, 3);
566     rx_SetStackSize(tservice, 10000);
567
568     /* allow super users to manage RX statistics */
569     rx_SetRxStatUserOk(BU_rxstat_userok);
570
571     /* misc. initialization */
572
573     /* database dump synchronization */
574     memset(dumpSyncPtr, 0, sizeof(*dumpSyncPtr));
575     Lock_Init(&dumpSyncPtr->ds_lock);
576
577     rx_StartServer(0);          /* start handling requests */
578
579     code = InitProcs();
580     if (code)
581         ERROR(code);
582
583
584     currentTime = time(0);
585     LogError(0, "Ready to process requests at %s\n", ctime(&currentTime));
586
587     rx_ServerProc(NULL);                /* donate this LWP */
588
589   error_exit:
590     osi_audit(BUDB_FinishEvent, code, AUD_END);
591     return (code);
592 }
593
594 void
595 consistencyCheckDb()
596 {
597     /* do consistency checks on structure sizes */
598     if ((sizeof(struct htBlock) > BLOCKSIZE)
599         || (sizeof(struct vfBlock) > BLOCKSIZE)
600         || (sizeof(struct viBlock) > BLOCKSIZE)
601         || (sizeof(struct dBlock) > BLOCKSIZE)
602         || (sizeof(struct tBlock) > BLOCKSIZE)
603         ) {
604         fprintf(stderr, "Block layout error!\n");
605         BUDB_EXIT(99);
606     }
607 }
608
609  /*VARARGS*/
610 LogDebug(level, a, b, c, d, e, f, g, h, i)
611      int level;
612      char *a, *b, *c, *d, *e, *f, *g, *h, *i;
613 {
614
615     if (debugging >= level) {
616         /* log normally closed so can remove it */
617         globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
618         if (globalConfPtr->log != NULL) {
619             fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
620             fflush(globalConfPtr->log);
621             fclose(globalConfPtr->log);
622         }
623     }
624     return 0;
625 }
626
627 static char *
628 TimeStamp(time_t t)
629 {
630     struct tm *lt;
631     static char timestamp[20];
632
633     lt = localtime(&t);
634     strftime(timestamp, 20, "%m/%d/%Y %T", lt);
635     return timestamp;
636 }
637
638  /*VARARGS*/
639 Log(a, b, c, d, e, f, g, h, i)
640      char *a, *b, *c, *d, *e, *f, *g, *h, *i;
641 {
642     time_t now;
643
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         fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
650         fflush(globalConfPtr->log);
651         fclose(globalConfPtr->log);
652     }
653     return 0;
654 }
655
656  /*VARARGS*/
657 LogError(code, a, b, c, d, e, f, g, h, i)
658      long code;
659      char *a, *b, *c, *d, *e, *f, *g, *h, *i;
660 {
661     time_t now;
662
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         fprintf(globalConfPtr->log, a, b, c, d, e, f, g, h, i);
673         fflush(globalConfPtr->log);
674         fclose(globalConfPtr->log);
675     }
676     return 0;
677 }
678
679
680 /*  ----------------
681  * debug
682  * ----------------
683  */
684
685
686 LogNetDump(dumpPtr)
687      struct dump *dumpPtr;
688 {
689     struct dump hostDump;
690     extern buServerConfP globalConfPtr;
691
692     dump_ntoh(dumpPtr, &hostDump);
693
694     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
695     if (globalConfPtr->log != NULL) {
696         printDump(globalConfPtr->log, &hostDump);
697         fclose(globalConfPtr->log);
698     }
699     return 0;
700 }