396830c63ed7a9a30d6a5ae071b3dbb4dca9fbcb
[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 #include <string.h>
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
33 #ifdef  AFS_AIX32_ENV
34 #include <signal.h>
35 #endif
36 #include <lwp.h>
37 #include <rx/xdr.h>
38 #include <rx/rx.h>
39 #include <rx/rxkad.h>
40 #include <rx/rx_globals.h>
41 #include <afs/cellconfig.h>
42 #include <lock.h>
43 #include <afs/afsutil.h>
44 #include <afs/com_err.h>
45 #include <ubik.h>
46 #include <sys/stat.h>
47 #include "kauth.h"
48 #include "kautils.h"
49 #include "kaserver.h"
50
51
52 struct kadstats dynamic_statistics;
53 struct ubik_dbase *KA_dbase;
54 afs_int32 myHost = 0;
55 afs_int32 verbose_track = 1;
56 afs_int32 krb4_cross = 0;
57 afs_int32 rxBind = 0;
58
59 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
60 afs_uint32 SHostAddrs[ADDRSPERSITE];
61
62 struct afsconf_dir *KA_conf;    /* for getting cell info */
63
64 int MinHours = 0;
65 int npwSums = KA_NPWSUMS;       /* needs to be variable sometime */
66
67 #include <stdarg.h>
68 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
69 #undef vfprintf
70 #define vfprintf(stream,fmt,args) _doprnt(fmt,args,stream)
71 #endif
72
73 static int debugOutput;
74
75 /* check whether caller is authorized to manage RX statistics */
76 int
77 KA_rxstat_userok(call)
78      struct rx_call *call;
79 {
80     return afsconf_SuperUser(KA_conf, call, NULL);
81 }
82
83 afs_int32
84 es_Report(char *fmt, ...)
85 {
86     va_list pvar;
87
88     if (debugOutput == 0)
89         return 0;
90     va_start(pvar, fmt);
91     vfprintf(stderr, fmt, pvar);
92     va_end(pvar);
93     return 0;
94 }
95
96 static void
97 initialize_dstats()
98 {
99     memset(&dynamic_statistics, 0, sizeof(dynamic_statistics));
100     dynamic_statistics.start_time = time(0);
101     dynamic_statistics.host = myHost;
102 }
103
104 static int
105 convert_cell_to_ubik(cellinfo, myHost, serverList)
106      struct afsconf_cell *cellinfo;
107      afs_int32 *myHost;
108      afs_int32 *serverList;
109 {
110     int i;
111     char hostname[64];
112     struct hostent *th;
113
114     /* get this host */
115     gethostname(hostname, sizeof(hostname));
116     th = gethostbyname(hostname);
117     if (!th) {
118         ViceLog(0, ("kaserver: couldn't get address of this host.\n"));
119         exit(1);
120     }
121     memcpy(myHost, th->h_addr, sizeof(afs_int32));
122
123     for (i = 0; i < cellinfo->numServers; i++)
124         if (cellinfo->hostAddr[i].sin_addr.s_addr != *myHost) {
125             /* omit my host from serverList */
126             *serverList++ = cellinfo->hostAddr[i].sin_addr.s_addr;
127         }
128     *serverList = 0;            /* terminate list */
129     return 0;
130 }
131
132 static afs_int32
133 kvno_admin_key(rock, kvno, key)
134      char *rock;
135      afs_int32 kvno;
136      struct ktc_encryptionKey *key;
137 {
138     return ka_LookupKvno(0, KA_ADMIN_NAME, KA_ADMIN_INST, kvno, key);
139
140     /* we would like to start a Ubik transaction to fill the cache if that
141      * fails, but may deadlock as Rx is now organized. */
142 }
143
144 /* initFlags: 0x01  Do not require authenticated connections.
145               0x02  Do not check the bos NoAuth flag
146               0x04  Use fast key expiration to test oldkey code.
147               0x08  Temporary flag allowing database inconsistency fixup
148  */
149
150 #include "AFS_component_version_number.c"
151
152 main(argc, argv)
153      int argc;
154      char *argv[];
155 {
156     afs_int32 code;
157     char *whoami = argv[0];
158     afs_int32 serverList[MAXSERVERS];
159     struct afsconf_cell cellinfo;
160     char *cell;
161     const char *cellservdb, *dbpath, *lclpath;
162     int a;
163     char arg[32];
164     char default_lclpath[AFSDIR_PATH_MAX];
165     int servers;
166     int initFlags;
167     int level;                  /* security level for Ubik */
168     afs_int32 i;
169     char clones[MAXHOSTSPERCELL];
170     afs_uint32 host = ntohl(INADDR_ANY);
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>] [-rxbind] "
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("-rxbind"))
309             rxBind = 1;
310         else if (IsArg("-minhours")) {
311             MinHours = atoi(argv[++a]);
312         } else if (IsArg("-enable_peer_stats")) {
313             rx_enablePeerRPCStats();
314         } else if (IsArg("-enable_process_stats")) {
315             rx_enableProcessRPCStats();
316         } else if (*arg == '-') {
317             /* hack to support help flag */
318             goto usage;
319         }
320     }
321     if (code = ka_CellConfig(cellservdb))
322         goto abort;
323     cell = ka_LocalCell();
324     KA_conf = afsconf_Open(cellservdb);
325     if (!KA_conf) {
326         code = KANOCELLS;
327       abort:
328         afs_com_err(whoami, code, "Failed getting cell info");
329         exit(1);
330     }
331 #ifdef        AUTH_DBM_LOG
332     kalog_Init();
333 #else
334     /* NT & HPUX do not have dbm package support. So we can only do some
335      * text logging. So open the AuthLog file for logging and redirect
336      * stdin and stdout to it 
337      */
338     OpenLog(AFSDIR_SERVER_KALOG_FILEPATH);
339     SetupLogSignals();
340 #endif
341
342     fprintf(stderr, "%s: WARNING: kaserver is deprecated due to its weak security "
343             "properties.  Migrating to a Kerberos 5 KDC is advised.  "
344             "http://www.openafs.org/no-more-des.html\n", whoami);
345     ViceLog(0, ("WARNING: kaserver is deprecated due to its weak security properties.  "
346             "Migrating to a Kerberos 5 KDC is advised.  "
347             "http://www.openafs.org/no-more-des.html\n"));
348
349     code =
350         afsconf_GetExtendedCellInfo(KA_conf, cell, AFSCONF_KAUTHSERVICE,
351                                     &cellinfo, &clones);
352     if (servers) {
353         if (code = ubik_ParseServerList(argc, argv, &myHost, serverList)) {
354             afs_com_err(whoami, code, "Couldn't parse server list");
355             exit(1);
356         }
357         cellinfo.hostAddr[0].sin_addr.s_addr = myHost;
358         for (i = 1; i < MAXSERVERS; i++) {
359             if (!serverList[i])
360                 break;
361             cellinfo.hostAddr[i].sin_addr.s_addr = serverList[i];
362         }
363         cellinfo.numServers = i;
364     } else {
365         code = convert_cell_to_ubik(&cellinfo, &myHost, serverList);
366         if (code)
367             goto abort;
368         ViceLog(0, ("Using server list from %s cell database.\n", cell));
369     }
370
371     /* initialize ubik */
372     if (level == rxkad_clear)
373         ubik_CRXSecurityProc = afsconf_ClientAuth;
374     else if (level == rxkad_crypt)
375         ubik_CRXSecurityProc = afsconf_ClientAuthSecure;
376     else {
377         ViceLog(0, ("Unsupported security level %d\n", level));
378         exit(5);
379     }
380     ViceLog(0,
381             ("Using level %s for Ubik connections.\n",
382              (level == rxkad_crypt ? "crypt" : "clear")));
383     ubik_CRXSecurityRock = (char *)KA_conf;
384     ubik_SRXSecurityProc = afsconf_ServerAuth;
385     ubik_SRXSecurityRock = (char *)KA_conf;
386     ubik_CheckRXSecurityProc = afsconf_CheckAuth;
387     ubik_CheckRXSecurityRock = (char *)KA_conf;
388
389     ubik_nBuffers = 80;
390
391     if (rxBind) {
392         afs_int32 ccode;
393 #ifndef AFS_NT40_ENV
394         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH || 
395             AFSDIR_SERVER_NETINFO_FILEPATH) {
396             char reason[1024];
397             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
398                                            ADDRSPERSITE, reason,
399                                            AFSDIR_SERVER_NETINFO_FILEPATH,
400                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
401         } else 
402 #endif  
403         {
404             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
405         }
406         if (ccode == 1) {
407             host = SHostAddrs[0];
408             rx_InitHost(host, htons(AFSCONF_KAUTHPORT));
409         }
410     }
411
412     if (servers)
413         code =
414             ubik_ServerInit(myHost, htons(AFSCONF_KAUTHPORT), serverList,
415                             dbpath, &KA_dbase);
416     else
417         code =
418             ubik_ServerInitByInfo(myHost, htons(AFSCONF_KAUTHPORT), &cellinfo,
419                                   &clones, dbpath, &KA_dbase);
420
421     if (code) {
422         afs_com_err(whoami, code, "Ubik init failed");
423         exit(2);
424     }
425
426     sca[RX_SCINDEX_NULL] = rxnull_NewServerSecurityObject();
427
428     /* Disable jumbograms */
429     rx_SetNoJumbo();
430
431     tservice =
432         rx_NewServiceHost(host, 0, KA_AUTHENTICATION_SERVICE, 
433                           "AuthenticationService", sca, 1, KAA_ExecuteRequest);
434     if (tservice == (struct rx_service *)0) {
435         ViceLog(0, ("Could not create Authentication rx service\n"));
436         exit(3);
437     }
438     rx_SetMinProcs(tservice, 1);
439     rx_SetMaxProcs(tservice, 1);
440
441     
442     tservice =
443         rx_NewServiceHost(host, 0, KA_TICKET_GRANTING_SERVICE, "TicketGrantingService",
444                       sca, 1, KAT_ExecuteRequest);
445     if (tservice == (struct rx_service *)0) {
446         ViceLog(0, ("Could not create Ticket Granting rx service\n"));
447         exit(3);
448     }
449     rx_SetMinProcs(tservice, 1);
450     rx_SetMaxProcs(tservice, 1);
451
452     scm[RX_SCINDEX_NULL] = sca[RX_SCINDEX_NULL];
453     scm[RX_SCINDEX_VAB] = 0;
454     scm[RX_SCINDEX_KAD] =
455         rxkad_NewServerSecurityObject(rxkad_crypt, 0, kvno_admin_key, 0);
456     tservice =
457         rx_NewServiceHost(host, 0, KA_MAINTENANCE_SERVICE, "Maintenance", scm, 3,
458                       KAM_ExecuteRequest);
459     if (tservice == (struct rx_service *)0) {
460         ViceLog(0, ("Could not create Maintenance rx service\n"));
461         exit(3);
462     }
463     rx_SetMinProcs(tservice, 1);
464     rx_SetMaxProcs(tservice, 1);
465     rx_SetStackSize(tservice, 10000);
466
467     tservice =
468         rx_NewServiceHost(host, 0, RX_STATS_SERVICE_ID, "rpcstats", scm, 3,
469                       RXSTATS_ExecuteRequest);
470     if (tservice == (struct rx_service *)0) {
471         ViceLog(0, ("Could not create rpc stats rx service\n"));
472         exit(3);
473     }
474     rx_SetMinProcs(tservice, 2);
475     rx_SetMaxProcs(tservice, 4);
476
477     initialize_dstats();
478
479     /* allow super users to manage RX statistics */
480     rx_SetRxStatUserOk(KA_rxstat_userok);
481
482     rx_StartServer(0);          /* start handling req. of all types */
483
484     if (init_kaprocs(lclpath, initFlags))
485         return -1;
486
487     if (code = init_krb_udp()) {
488         ViceLog(0,
489                 ("Failed to initialize UDP interface; code = %d.\n", code));
490         ViceLog(0, ("Running without UDP access.\n"));
491     }
492
493     ViceLog(0, ("Starting to process AuthServer requests\n"));
494     rx_ServerProc(NULL);                /* donate this LWP */
495     return 0;
496 }