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