c1ea8a5c7c605a8e4b31cc4c2898b3b6724c9974
[openafs.git] / src / kauth / kaserver.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 <afs/stds.h>
17 #include <sys/types.h>
18 #ifdef AFS_NT40_ENV
19 #include <winsock2.h>
20 #include <WINNT/afsevent.h>
21 #else
22 #include <sys/file.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #endif
26 #include "kalog.h"              /* for OpenLog() */
27 #include <time.h>
28 #include <stdio.h>
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #else
32 #ifdef HAVE_STRINGS_H
33 #include <strings.h>
34 #endif
35 #endif
36 #ifdef HAVE_FCNTL_H
37 #include <fcntl.h>
38 #endif
39 #ifdef  AFS_AIX32_ENV
40 #include <signal.h>
41 #endif
42 #include <lwp.h>
43 #include <rx/xdr.h>
44 #include <rx/rx.h>
45 #include <rx/rxkad.h>
46 #include <rx/rx_globals.h>
47 #include <afs/cellconfig.h>
48 #include <lock.h>
49 #include <afs/afsutil.h>
50 #include <ubik.h>
51 #include <sys/stat.h>
52 #include "kauth.h"
53 #include "kautils.h"
54 #include "kaserver.h"
55
56
57 struct kadstats dynamic_statistics;
58 struct ubik_dbase *KA_dbase;
59 afs_int32 myHost = 0;
60 afs_int32 verbose_track = 1;
61 afs_int32 krb4_cross = 0;
62
63 struct afsconf_dir *KA_conf;    /* for getting cell info */
64
65 int MinHours = 0;
66 int npwSums = KA_NPWSUMS;       /* needs to be variable sometime */
67
68 #include <stdarg.h>
69 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
70 #undef vfprintf
71 #define vfprintf(stream,fmt,args) _doprnt(fmt,args,stream)
72 #endif
73
74 static int debugOutput;
75
76 /* check whether caller is authorized to manage RX statistics */
77 int
78 KA_rxstat_userok(call)
79      struct rx_call *call;
80 {
81     return afsconf_SuperUser(KA_conf, call, NULL);
82 }
83
84 afs_int32
85 es_Report(char *fmt, ...)
86 {
87     va_list pvar;
88
89     if (debugOutput == 0)
90         return 0;
91     va_start(pvar, fmt);
92     vfprintf(stderr, fmt, pvar);
93     va_end(pvar);
94     return 0;
95 }
96
97 static void
98 initialize_dstats()
99 {
100     memset(&dynamic_statistics, 0, sizeof(dynamic_statistics));
101     dynamic_statistics.start_time = time(0);
102     dynamic_statistics.host = myHost;
103 }
104
105 static int
106 convert_cell_to_ubik(cellinfo, myHost, serverList)
107      struct afsconf_cell *cellinfo;
108      afs_int32 *myHost;
109      afs_int32 *serverList;
110 {
111     int i;
112     char hostname[64];
113     struct hostent *th;
114
115     /* get this host */
116     gethostname(hostname, sizeof(hostname));
117     th = gethostbyname(hostname);
118     if (!th) {
119         ViceLog(0, ("kaserver: couldn't get address of this host.\n"));
120         exit(1);
121     }
122     memcpy(myHost, th->h_addr, sizeof(afs_int32));
123
124     for (i = 0; i < cellinfo->numServers; i++)
125         if (cellinfo->hostAddr[i].sin_addr.s_addr != *myHost) {
126             /* omit my host from serverList */
127             *serverList++ = cellinfo->hostAddr[i].sin_addr.s_addr;
128         }
129     *serverList = 0;            /* terminate list */
130     return 0;
131 }
132
133 static afs_int32
134 kvno_admin_key(rock, kvno, key)
135      char *rock;
136      afs_int32 kvno;
137      struct ktc_encryptionKey *key;
138 {
139     return ka_LookupKvno(0, KA_ADMIN_NAME, KA_ADMIN_INST, kvno, key);
140
141     /* we would like to start a Ubik transaction to fill the cache if that
142      * fails, but may deadlock as Rx is now organized. */
143 }
144
145 /* initFlags: 0x01  Do not require authenticated connections.
146               0x02  Do not check the bos NoAuth flag
147               0x04  Use fast key expiration to test oldkey code.
148               0x08  Temporary flag allowing database inconsistency fixup
149  */
150
151 #include "AFS_component_version_number.c"
152
153 main(argc, argv)
154      int argc;
155      char *argv[];
156 {
157     afs_int32 code;
158     char *whoami = argv[0];
159     afs_int32 serverList[MAXSERVERS];
160     struct afsconf_cell cellinfo;
161     char *cell;
162     const char *cellservdb, *dbpath, *lclpath;
163     int a;
164     char arg[32];
165     char default_lclpath[AFSDIR_PATH_MAX];
166     int servers;
167     int initFlags;
168     int level;                  /* security level for Ubik */
169     afs_int32 i;
170     char clones[MAXHOSTSPERCELL];
171
172     struct rx_service *tservice;
173     struct rx_securityClass *sca[1];
174     struct rx_securityClass *scm[3];
175
176     extern int afsconf_ClientAuthSecure();
177     extern int afsconf_ServerAuth();
178     extern int afsconf_CheckAuth();
179
180     extern int rx_stackSize;
181     extern int KAA_ExecuteRequest();
182     extern int KAT_ExecuteRequest();
183     extern int KAM_ExecuteRequest();
184     extern int RXSTATS_ExecuteRequest();
185
186 #ifdef  AFS_AIX32_ENV
187     /*
188      * The following signal action for AIX is necessary so that in case of a 
189      * crash (i.e. core is generated) we can include the user's data section 
190      * in the core dump. Unfortunately, by default, only a partial core is
191      * generated which, in many cases, isn't too useful.
192      */
193     struct sigaction nsa;
194
195     sigemptyset(&nsa.sa_mask);
196     nsa.sa_handler = SIG_DFL;
197     nsa.sa_flags = SA_FULLDUMP;
198     sigaction(SIGABRT, &nsa, NULL);
199     sigaction(SIGSEGV, &nsa, NULL);
200 #endif
201     osi_audit_init();
202
203     if (argc == 0) {
204       usage:
205         printf("Usage: kaserver [-noAuth] [-fastKeys] [-database <dbpath>] "
206                "[-auditlog <log path>] "
207                "[-localfiles <lclpath>] [-minhours <n>] [-servers <serverlist>] "
208                "[-crossrealm]"
209                /*" [-enable_peer_stats] [-enable_process_stats] " */
210                "[-help]\n");
211         exit(1);
212     }
213 #ifdef AFS_NT40_ENV
214     /* initialize winsock */
215     if (afs_winsockInit() < 0) {
216         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
217         fprintf(stderr, "%s: Couldn't initialize winsock.\n", whoami);
218         exit(1);
219     }
220 #endif
221     /* Initialize dirpaths */
222     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
223 #ifdef AFS_NT40_ENV
224         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
225 #endif
226         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
227                 argv[0]);
228         exit(2);
229     }
230
231     cellservdb = AFSDIR_SERVER_ETC_DIRPATH;
232     dbpath = AFSDIR_SERVER_KADB_FILEPATH;
233     strcompose(default_lclpath, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH,
234                "/", AFSDIR_KADB_FILE, NULL);
235     lclpath = default_lclpath;
236
237     debugOutput = 0;
238     servers = 0;
239     initFlags = 0;
240     level = rxkad_crypt;
241     for (a = 1; a < argc; a++) {
242         int arglen = strlen(argv[a]);
243         lcstring(arg, argv[a], sizeof(arg));
244 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
245
246         if (strcmp(arg, "-database") == 0) {
247             dbpath = argv[++a];
248             if (strcmp(lclpath, default_lclpath) == 0)
249                 lclpath = dbpath;
250         }
251         else if (strncmp(arg, "-auditlog", arglen) == 0) {
252             int tempfd, flags;
253             FILE *auditout;
254             char oldName[MAXPATHLEN];
255             char *fileName = argv[++a];
256             
257 #ifndef AFS_NT40_ENV
258             struct stat statbuf;
259             
260             if ((lstat(fileName, &statbuf) == 0) 
261                 && (S_ISFIFO(statbuf.st_mode))) {
262                 flags = O_WRONLY | O_NONBLOCK;
263             } else 
264 #endif
265             {
266                 strcpy(oldName, fileName);
267                 strcat(oldName, ".old");
268                 renamefile(fileName, oldName);
269                 flags = O_WRONLY | O_TRUNC | O_CREAT;
270             }
271             tempfd = open(fileName, flags, 0666);
272             if (tempfd > -1) {
273                 auditout = fdopen(tempfd, "a");
274                 if (auditout) {
275                     osi_audit_file(auditout);
276                 } else
277                     printf("Warning: auditlog %s not writable, ignored.\n", fileName);
278             } else
279                 printf("Warning: auditlog %s not writable, ignored.\n", fileName);
280         } else if (strcmp(arg, "-localfiles") == 0)
281             lclpath = argv[++a];
282         else if (strcmp(arg, "-servers") == 0)
283             debugOutput++, servers = 1;
284         else if (strcmp(arg, "-noauth") == 0)
285             debugOutput++, initFlags |= 1;
286         else if (strcmp(arg, "-fastkeys") == 0)
287             debugOutput++, initFlags |= 4;
288         else if (strcmp(arg, "-dbfixup") == 0)
289             debugOutput++, initFlags |= 8;
290         else if (strcmp(arg, "-cellservdb") == 0) {
291             cellservdb = argv[++a];
292             initFlags |= 2;
293             debugOutput++;
294         }
295
296         else if (IsArg("-crypt"))
297             level = rxkad_crypt;
298         else if (IsArg("-safe"))
299             level = rxkad_crypt;
300         else if (IsArg("-clear"))
301             level = rxkad_clear;
302         else if (IsArg("-sorry"))
303             level = rxkad_clear;
304         else if (IsArg("-debug"))
305             verbose_track = 0;
306         else if (IsArg("-crossrealm"))
307             krb4_cross = 1;
308         else if (IsArg("-minhours")) {
309             MinHours = atoi(argv[++a]);
310         } else if (IsArg("-enable_peer_stats")) {
311             rx_enablePeerRPCStats();
312         } else if (IsArg("-enable_process_stats")) {
313             rx_enableProcessRPCStats();
314         } else if (*arg == '-') {
315             /* hack to support help flag */
316             goto usage;
317         }
318     }
319     if (code = ka_CellConfig(cellservdb))
320         goto abort;
321     cell = ka_LocalCell();
322     KA_conf = afsconf_Open(cellservdb);
323     if (!KA_conf) {
324         code = KANOCELLS;
325       abort:
326         com_err(whoami, code, "Failed getting cell info");
327         exit(1);
328     }
329 #ifdef        AUTH_DBM_LOG
330     kalog_Init();
331 #else
332     /* NT & HPUX do not have dbm package support. So we can only do some
333      * text logging. So open the AuthLog file for logging and redirect
334      * stdin and stdout to it 
335      */
336     OpenLog(AFSDIR_SERVER_KALOG_FILEPATH);
337     SetupLogSignals();
338 #endif
339     code =
340         afsconf_GetExtendedCellInfo(KA_conf, cell, AFSCONF_KAUTHSERVICE,
341                                     &cellinfo, &clones);
342     if (servers) {
343         if (code = ubik_ParseServerList(argc, argv, &myHost, serverList)) {
344             com_err(whoami, code, "Couldn't parse server list");
345             exit(1);
346         }
347         cellinfo.hostAddr[0].sin_addr.s_addr = myHost;
348         for (i = 1; i < MAXSERVERS; i++) {
349             if (!serverList[i])
350                 break;
351             cellinfo.hostAddr[i].sin_addr.s_addr = serverList[i];
352         }
353         cellinfo.numServers = i;
354     } else {
355         code = convert_cell_to_ubik(&cellinfo, &myHost, serverList);
356         if (code)
357             goto abort;
358         ViceLog(0, ("Using server list from %s cell database.\n", cell));
359     }
360
361     /* initialize ubik */
362     if (level == rxkad_clear)
363         ubik_CRXSecurityProc = afsconf_ClientAuth;
364     else if (level == rxkad_crypt)
365         ubik_CRXSecurityProc = afsconf_ClientAuthSecure;
366     else {
367         ViceLog(0, ("Unsupported security level %d\n", level));
368         exit(5);
369     }
370     ViceLog(0,
371             ("Using level %s for Ubik connections.\n",
372              (level == rxkad_crypt ? "crypt" : "clear")));
373     ubik_CRXSecurityRock = (char *)KA_conf;
374     ubik_SRXSecurityProc = afsconf_ServerAuth;
375     ubik_SRXSecurityRock = (char *)KA_conf;
376     ubik_CheckRXSecurityProc = afsconf_CheckAuth;
377     ubik_CheckRXSecurityRock = (char *)KA_conf;
378
379     ubik_nBuffers = 80;
380     if (servers)
381         code =
382             ubik_ServerInit(myHost, htons(AFSCONF_KAUTHPORT), serverList,
383                             dbpath, &KA_dbase);
384     else
385         code =
386             ubik_ServerInitByInfo(myHost, htons(AFSCONF_KAUTHPORT), &cellinfo,
387                                   &clones, dbpath, &KA_dbase);
388
389     if (code) {
390         com_err(whoami, code, "Ubik init failed");
391         exit(2);
392     }
393
394     sca[RX_SCINDEX_NULL] = rxnull_NewServerSecurityObject();
395
396     /* Disable jumbograms */
397     rx_SetNoJumbo();
398
399     tservice =
400         rx_NewService(0, KA_AUTHENTICATION_SERVICE, "AuthenticationService",
401                       sca, 1, KAA_ExecuteRequest);
402     if (tservice == (struct rx_service *)0) {
403         ViceLog(0, ("Could not create Authentication rx service\n"));
404         exit(3);
405     }
406     rx_SetMinProcs(tservice, 1);
407     rx_SetMaxProcs(tservice, 1);
408
409     tservice =
410         rx_NewService(0, KA_TICKET_GRANTING_SERVICE, "TicketGrantingService",
411                       sca, 1, KAT_ExecuteRequest);
412     if (tservice == (struct rx_service *)0) {
413         ViceLog(0, ("Could not create Ticket Granting rx service\n"));
414         exit(3);
415     }
416     rx_SetMinProcs(tservice, 1);
417     rx_SetMaxProcs(tservice, 1);
418
419     scm[RX_SCINDEX_NULL] = sca[RX_SCINDEX_NULL];
420     scm[RX_SCINDEX_VAB] = 0;
421     scm[RX_SCINDEX_KAD] =
422         rxkad_NewServerSecurityObject(rxkad_crypt, 0, kvno_admin_key, 0);
423     tservice =
424         rx_NewService(0, KA_MAINTENANCE_SERVICE, "Maintenance", scm, 3,
425                       KAM_ExecuteRequest);
426     if (tservice == (struct rx_service *)0) {
427         ViceLog(0, ("Could not create Maintenance rx service\n"));
428         exit(3);
429     }
430     rx_SetMinProcs(tservice, 1);
431     rx_SetMaxProcs(tservice, 1);
432     rx_SetStackSize(tservice, 10000);
433
434     tservice =
435         rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", scm, 3,
436                       RXSTATS_ExecuteRequest);
437     if (tservice == (struct rx_service *)0) {
438         ViceLog(0, ("Could not create rpc stats rx service\n"));
439         exit(3);
440     }
441     rx_SetMinProcs(tservice, 2);
442     rx_SetMaxProcs(tservice, 4);
443
444     initialize_dstats();
445
446     /* allow super users to manage RX statistics */
447     rx_SetRxStatUserOk(KA_rxstat_userok);
448
449     rx_StartServer(0);          /* start handling req. of all types */
450
451     if (init_kaprocs(lclpath, initFlags))
452         return -1;
453
454     if (code = init_krb_udp()) {
455         ViceLog(0,
456                 ("Failed to initialize UDP interface; code = %d.\n", code));
457         ViceLog(0, ("Running without UDP access.\n"));
458     }
459
460     ViceLog(0, ("Starting to process AuthServer requests\n"));
461     rx_ServerProc();            /* donate this LWP */
462     return 0;
463 }