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