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