584b6113d4e7c822b80bf8340750d8eec7959d63
[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;
167     int servers;
168     int initFlags;
169     int level;                  /* security level for Ubik */
170     afs_int32 i;
171     char clones[MAXHOSTSPERCELL];
172     char hoststr[16];
173     afs_uint32 host = ntohl(INADDR_ANY);
174     char *auditFileName = NULL;
175     struct logOptions logopts;
176
177     struct rx_service *tservice;
178     struct rx_securityClass *sca[1];
179     struct rx_securityClass *scm[3];
180
181     extern int rx_stackSize;
182
183 #ifdef  AFS_AIX32_ENV
184     /*
185      * The following signal action for AIX is necessary so that in case of a
186      * crash (i.e. core is generated) we can include the user's data section
187      * in the core dump. Unfortunately, by default, only a partial core is
188      * generated which, in many cases, isn't too useful.
189      */
190     struct sigaction nsa;
191
192     sigemptyset(&nsa.sa_mask);
193     nsa.sa_handler = SIG_DFL;
194     nsa.sa_flags = SA_FULLDUMP;
195     sigaction(SIGABRT, &nsa, NULL);
196     sigaction(SIGSEGV, &nsa, NULL);
197 #endif
198     osi_audit_init();
199
200     memset(&logopts, 0, sizeof(logopts));
201
202     if (argc == 0) {
203       usage:
204         printf("Usage: kaserver [-noAuth] [-database <dbpath>] "
205                "[-auditlog <log path>] [-audit-interface <file|sysvmq>] "
206                "[-rxbind] [-localfiles <lclpath>] [-minhours <n>] "
207                "[-servers <serverlist>] [-crossrealm] "
208                "[-enable_peer_stats] [-enable_process_stats] "
209                "[-help]\n");
210         exit(1);
211     }
212 #ifdef AFS_NT40_ENV
213     /* initialize winsock */
214     if (afs_winsockInit() < 0) {
215         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
216         fprintf(stderr, "%s: Couldn't initialize winsock.\n", whoami);
217         exit(1);
218     }
219 #endif
220     /* Initialize dirpaths */
221     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
222 #ifdef AFS_NT40_ENV
223         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
224 #endif
225         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
226                 argv[0]);
227         exit(2);
228     }
229
230     cellservdb = AFSDIR_SERVER_ETC_DIRPATH;
231     dbpath = AFSDIR_SERVER_KADB_FILEPATH;
232
233     if (asprintf(&default_lclpath, "%s/%s", AFSDIR_SERVER_LOCAL_DIRPATH,
234                  AFSDIR_KADB_FILE) < 0) {
235         fprintf(stderr, "%s: No memory for default local dir path\n", argv[0]);
236         exit(2);
237     }
238     lclpath = default_lclpath;
239
240     debugOutput = 0;
241     servers = 0;
242     initFlags = 0;
243     level = rxkad_crypt;
244     for (a = 1; a < argc; a++) {
245         int arglen = strlen(argv[a]);
246         lcstring(arg, argv[a], sizeof(arg));
247 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
248
249         if (strcmp(arg, "-database") == 0) {
250             dbpath = argv[++a];
251             if (strcmp(lclpath, default_lclpath) == 0)
252                 lclpath = dbpath;
253         }
254         else if (strncmp(arg, "-auditlog", arglen) == 0) {
255             auditFileName = argv[++a];
256
257         } else if (strncmp(arg, "-audit-interface", arglen) == 0) {
258             char *interface = argv[++a];
259
260             if (osi_audit_interface(interface)) {
261                 printf("Invalid audit interface '%s'\n", interface);
262                 exit(1);
263             }
264
265         } else if (strcmp(arg, "-localfiles") == 0)
266             lclpath = argv[++a];
267         else if (strcmp(arg, "-servers") == 0)
268             debugOutput++, servers = 1;
269         else if (strcmp(arg, "-noauth") == 0)
270             debugOutput++, initFlags |= 1;
271         else if (strcmp(arg, "-fastkeys") == 0)
272             debugOutput++, initFlags |= 4;
273         else if (strcmp(arg, "-dbfixup") == 0)
274             debugOutput++, initFlags |= 8;
275         else if (strcmp(arg, "-cellservdb") == 0) {
276             cellservdb = argv[++a];
277             initFlags |= 2;
278             debugOutput++;
279         }
280
281         else if (IsArg("-crypt"))
282             level = rxkad_crypt;
283         else if (IsArg("-safe"))
284             level = rxkad_crypt;
285         else if (IsArg("-clear"))
286             level = rxkad_clear;
287         else if (IsArg("-sorry"))
288             level = rxkad_clear;
289         else if (IsArg("-debug"))
290             verbose_track = 0;
291         else if (IsArg("-crossrealm"))
292             krb4_cross = 1;
293         else if (IsArg("-rxbind"))
294             rxBind = 1;
295         else if (IsArg("-minhours")) {
296             MinHours = atoi(argv[++a]);
297         } else if (IsArg("-enable_peer_stats")) {
298             rx_enablePeerRPCStats();
299         } else if (IsArg("-enable_process_stats")) {
300             rx_enableProcessRPCStats();
301         } else if (*arg == '-') {
302             /* hack to support help flag */
303             goto usage;
304         }
305     }
306
307     if (auditFileName) {
308         osi_audit_file(auditFileName);
309     }
310
311     if ((code = ka_CellConfig(cellservdb)))
312         goto abort;
313     cell = ka_LocalCell();
314     KA_conf = afsconf_Open(cellservdb);
315     if (!KA_conf) {
316         code = KANOCELLS;
317       abort:
318         afs_com_err(whoami, code, "Failed getting cell info");
319         exit(1);
320     }
321 #ifdef        AUTH_DBM_LOG
322     kalog_Init();
323 #else
324     /* NT & HPUX do not have dbm package support. So we can only do some
325      * text logging. So open the AuthLog file for logging and redirect
326      * stdin and stdout to it
327      */
328     logopts.lopt_dest = logDest_file;
329     logopts.lopt_filename = AFSDIR_SERVER_KALOG_FILEPATH;
330     logopts.lopt_rotateOnOpen = 1;
331     logopts.lopt_rotateStyle = logRotate_old;
332
333     OpenLog(&logopts);
334     SetupLogSignals();
335 #endif
336
337     fprintf(stderr, "%s: WARNING: kaserver is deprecated due to its weak security "
338             "properties.  Migrating to a Kerberos 5 KDC is advised.  "
339             "http://www.openafs.org/no-more-des.html\n", whoami);
340     ViceLog(0, ("WARNING: kaserver is deprecated due to its weak security properties.  "
341             "Migrating to a Kerberos 5 KDC is advised.  "
342             "http://www.openafs.org/no-more-des.html\n"));
343
344     code = afsconf_GetExtendedCellInfo(KA_conf, cell, AFSCONF_KAUTHSERVICE,
345                                        &cellinfo, clones);
346     if (code) {
347         afs_com_err(whoami, code, "Couldn't read cell configuration");
348         exit(1);
349     }
350
351     if (servers) {
352         if ((code = ubik_ParseServerList(argc, argv, &myHost, serverList))) {
353             afs_com_err(whoami, code, "Couldn't parse server list");
354             exit(1);
355         }
356         cellinfo.hostAddr[0].sin_addr.s_addr = myHost;
357         for (i = 1; i < MAXSERVERS; i++) {
358             if (!serverList[i])
359                 break;
360             if (i >= MAXHOSTSPERCELL) {
361                 fprintf(stderr,
362                         "Too many ubik servers specified on command line\n");
363                 exit(1);
364             }
365             cellinfo.hostAddr[i].sin_addr.s_addr = serverList[i];
366         }
367         cellinfo.numServers = i;
368     } else {
369         code = convert_cell_to_ubik(&cellinfo, &myHost, serverList);
370         if (code)
371             goto abort;
372         ViceLog(0, ("Using server list from %s cell database.\n", cell));
373     }
374
375     /* initialize audit user check */
376     osi_audit_set_user_check(KA_conf, KA_IsLocalRealmMatch);
377
378     /* initialize ubik */
379     if (level == rxkad_clear)
380         ubik_SetClientSecurityProcs(afsconf_ClientAuth, afsconf_UpToDate,
381                                     KA_conf);
382     else if (level == rxkad_crypt)
383         ubik_SetClientSecurityProcs(afsconf_ClientAuthSecure,
384                                     afsconf_UpToDate, KA_conf);
385     else {
386         ViceLog(0, ("Unsupported security level %d\n", level));
387         exit(5);
388     }
389     ViceLog(0,
390             ("Using level %s for Ubik connections.\n",
391              (level == rxkad_crypt ? "crypt" : "clear")));
392
393     ubik_SetServerSecurityProcs(afsconf_BuildServerSecurityObjects,
394                                 afsconf_CheckAuth,
395                                 KA_conf);
396
397     ubik_nBuffers = 80;
398
399     if (rxBind) {
400         afs_int32 ccode;
401         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
402             AFSDIR_SERVER_NETINFO_FILEPATH) {
403             char reason[1024];
404             ccode = afsconf_ParseNetFiles(SHostAddrs, NULL, NULL,
405                                           ADDRSPERSITE, reason,
406                                           AFSDIR_SERVER_NETINFO_FILEPATH,
407                                           AFSDIR_SERVER_NETRESTRICT_FILEPATH);
408         } else
409         {
410             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
411         }
412         if (ccode == 1) {
413             host = SHostAddrs[0];
414         }
415     }
416
417     ViceLog(0, ("kaserver binding rx to %s:%d\n",
418             afs_inet_ntoa_r(host, hoststr), AFSCONF_KAUTHPORT));
419     code = rx_InitHost(host, htons(AFSCONF_KAUTHPORT));
420     if (code) {
421         afs_com_err(whoami, code, "rx init failed");
422         exit(2);
423     }
424
425     /* Disable jumbograms */
426     rx_SetNoJumbo();
427
428     if (servers)
429         code =
430             ubik_ServerInit(myHost, htons(AFSCONF_KAUTHPORT), serverList,
431                             dbpath, &KA_dbase);
432     else
433         code =
434             ubik_ServerInitByInfo(myHost, htons(AFSCONF_KAUTHPORT), &cellinfo,
435                                   clones, dbpath, &KA_dbase);
436
437     if (code) {
438         afs_com_err(whoami, code, "Ubik init failed");
439         exit(2);
440     }
441
442     sca[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
443
444     tservice =
445         rx_NewServiceHost(host, 0, KA_AUTHENTICATION_SERVICE,
446                           "AuthenticationService", sca, 1, KAA_ExecuteRequest);
447     if (tservice == (struct rx_service *)0) {
448         ViceLog(0, ("Could not create Authentication rx service\n"));
449         exit(3);
450     }
451     rx_SetMinProcs(tservice, 1);
452     rx_SetMaxProcs(tservice, 1);
453
454
455     tservice =
456         rx_NewServiceHost(host, 0, KA_TICKET_GRANTING_SERVICE, "TicketGrantingService",
457                       sca, 1, KAT_ExecuteRequest);
458     if (tservice == (struct rx_service *)0) {
459         ViceLog(0, ("Could not create Ticket Granting rx service\n"));
460         exit(3);
461     }
462     rx_SetMinProcs(tservice, 1);
463     rx_SetMaxProcs(tservice, 1);
464
465     scm[RX_SECIDX_NULL] = sca[RX_SECIDX_NULL];
466     scm[RX_SECIDX_VAB] = 0;
467     scm[RX_SECIDX_KAD] =
468         rxkad_NewServerSecurityObject(rxkad_crypt, 0, kvno_admin_key, 0);
469     tservice =
470         rx_NewServiceHost(host, 0, KA_MAINTENANCE_SERVICE, "Maintenance", scm, 3,
471                       KAM_ExecuteRequest);
472     if (tservice == (struct rx_service *)0) {
473         ViceLog(0, ("Could not create Maintenance rx service\n"));
474         exit(3);
475     }
476     rx_SetMinProcs(tservice, 1);
477     rx_SetMaxProcs(tservice, 1);
478     rx_SetStackSize(tservice, 10000);
479
480     tservice =
481         rx_NewServiceHost(host, 0, RX_STATS_SERVICE_ID, "rpcstats", scm, 3,
482                       RXSTATS_ExecuteRequest);
483     if (tservice == (struct rx_service *)0) {
484         ViceLog(0, ("Could not create rpc stats rx service\n"));
485         exit(3);
486     }
487     rx_SetMinProcs(tservice, 2);
488     rx_SetMaxProcs(tservice, 4);
489
490     initialize_dstats();
491
492     /* allow super users to manage RX statistics */
493     rx_SetRxStatUserOk(KA_rxstat_userok);
494
495     rx_StartServer(0);          /* start handling req. of all types */
496
497     if (init_kaprocs(lclpath, initFlags))
498         return -1;
499
500     if ((code = init_krb_udp())) {
501         ViceLog(0,
502                 ("Failed to initialize UDP interface; code = %d.\n", code));
503         ViceLog(0, ("Running without UDP access.\n"));
504     }
505
506     ViceLog(0, ("Starting to process AuthServer requests\n"));
507     rx_ServerProc(NULL);                /* donate this LWP */
508     return 0;
509 }