Commit | Line | Data |
---|---|---|
805e021f CE |
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 | ||
14 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
15 | #include "afsincludes.h" /* Afs-based standard headers */ | |
16 | #include "afs/afs_stats.h" | |
17 | #include "rx/rx_globals.h" | |
18 | #include "rx/rxstat.h" | |
19 | #if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV) | |
20 | #include "net/if.h" | |
21 | #include "netinet/in_var.h" | |
22 | #endif /* !defined(UKERNEL) */ | |
23 | #include "rmtsys.h" | |
24 | #include "pagcb.h" | |
25 | ||
26 | ||
27 | afs_int32 afs_termState = 0; | |
28 | afs_int32 afs_gcpags = AFS_GCPAGS; | |
29 | enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING; | |
30 | int afs_cold_shutdown = 0; | |
31 | int afs_resourceinit_flag = 0; | |
32 | afs_int32 afs_nfs_server_addr; | |
33 | struct interfaceAddr afs_cb_interface; | |
34 | struct afs_osi_WaitHandle AFS_WaitHandler; | |
35 | static struct rx_securityClass *srv_secobj; | |
36 | static struct rx_securityClass *clt_secobj; | |
37 | static struct rx_service *stats_svc; | |
38 | static struct rx_service *pagcb_svc; | |
39 | static struct rx_connection *rmtsys_conn; | |
40 | char *afs_sysname = 0; | |
41 | char *afs_sysnamelist[MAXNUMSYSNAMES]; | |
42 | int afs_sysnamecount = 0; | |
43 | int afs_sysnamegen = 0; | |
44 | afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */ | |
45 | ||
46 | ||
47 | void | |
48 | afs_Daemon(void) | |
49 | { | |
50 | afs_int32 now, last10MinCheck, last60MinCheck; | |
51 | ||
52 | last10MinCheck = 0; | |
53 | last60MinCheck = 0; | |
54 | while (1) { | |
55 | rx_CheckPackets(); | |
56 | now = osi_Time(); | |
57 | ||
58 | if (last10MinCheck + 600 < now) { | |
59 | afs_GCUserData(); | |
60 | } | |
61 | ||
62 | if (last60MinCheck + 3600 < now) { | |
63 | afs_int32 didany; | |
64 | afs_GCPAGs(&didany); | |
65 | } | |
66 | ||
67 | now = 20000 - (osi_Time() - now); | |
68 | afs_osi_Wait(now, &AFS_WaitHandler, 0); | |
69 | ||
70 | if (afs_termState == AFSOP_STOP_AFS) { | |
71 | #if defined(RXK_LISTENER_ENV) | |
72 | afs_termState = AFSOP_STOP_RXEVENT; | |
73 | #else | |
74 | afs_termState = AFSOP_STOP_COMPLETE; | |
75 | #endif | |
76 | afs_osi_Wakeup(&afs_termState); | |
77 | return; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | ||
83 | void | |
84 | afspag_Init(afs_int32 nfs_server_addr) | |
85 | { | |
86 | struct clientcred ccred; | |
87 | struct rmtbulk idata, odata; | |
88 | afs_int32 code, err, addr, obuf; | |
89 | int i; | |
90 | ||
91 | afs_uuid_create(&afs_cb_interface.uuid); | |
92 | ||
93 | AFS_GLOCK(); | |
94 | ||
95 | afs_InitStats(); | |
96 | rx_Init(htons(7001)); | |
97 | ||
98 | AFS_STATCNT(afs_ResourceInit); | |
99 | AFS_RWLOCK_INIT(&afs_xuser, "afs_xuser"); | |
100 | AFS_RWLOCK_INIT(&afs_xpagcell, "afs_xpagcell"); | |
101 | AFS_RWLOCK_INIT(&afs_xpagsys, "afs_xpagsys"); | |
102 | AFS_RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock"); | |
103 | ||
104 | afs_resourceinit_flag = 1; | |
105 | afs_nfs_server_addr = nfs_server_addr; | |
106 | for (i = 0; i < MAXNUMSYSNAMES; i++) { | |
107 | afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME); | |
108 | osi_Assert(afs_sysnamelist[i] != NULL); | |
109 | } | |
110 | afs_sysname = afs_sysnamelist[0]; | |
111 | strcpy(afs_sysname, SYS_NAME); | |
112 | afs_sysnamecount = 1; | |
113 | afs_sysnamegen++; | |
114 | ||
115 | srv_secobj = rxnull_NewServerSecurityObject(); | |
116 | stats_svc = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", &srv_secobj, | |
117 | 1, RXSTATS_ExecuteRequest); | |
118 | pagcb_svc = rx_NewService(0, PAGCB_SERVICEID, "pagcb", &srv_secobj, | |
119 | 1, PAGCB_ExecuteRequest); | |
120 | rx_StartServer(0); | |
121 | ||
122 | clt_secobj = rxnull_NewClientSecurityObject(); | |
123 | rmtsys_conn = rx_NewConnection(nfs_server_addr, htons(7009), | |
124 | RMTSYS_SERVICEID, clt_secobj, 0); | |
125 | ||
126 | #ifdef RXK_LISTENER_ENV | |
127 | afs_start_thread(rxk_Listener, "Rx Listener"); | |
128 | #endif | |
129 | afs_start_thread((void *)(void *)rx_ServerProc, "Rx Server Thread"); | |
130 | afs_start_thread(afs_rxevent_daemon, "Rx Event Daemon"); | |
131 | afs_start_thread(afs_Daemon, "AFS PAG Daemon"); | |
132 | ||
133 | afs_icl_InitLogs(); | |
134 | ||
135 | AFS_GUNLOCK(); | |
136 | ||
137 | /* If it's reachable, tell the translator to nuke our creds. | |
138 | * We should be more agressive about making sure this gets done, | |
139 | * even if the translator is unreachable when we boot. | |
140 | */ | |
141 | addr = obuf = err = 0; | |
142 | idata.rmtbulk_len = sizeof(addr); | |
143 | idata.rmtbulk_val = (char *)&addr; | |
144 | odata.rmtbulk_len = sizeof(obuf); | |
145 | odata.rmtbulk_val = (char *)&obuf; | |
146 | memset(&ccred, 0, sizeof(ccred)); | |
147 | code = RMTSYS_Pioctl(rmtsys_conn, &ccred, NIL_PATHP, 0x4F01, 0, | |
148 | &idata, &odata, &err); | |
149 | } /*afs_ResourceInit */ | |
150 | ||
151 | ||
152 | /* called with the GLOCK held */ | |
153 | void | |
154 | afspag_Shutdown(void) | |
155 | { | |
156 | if (afs_shuttingdown != AFS_RUNNING) | |
157 | return; | |
158 | afs_shuttingdown = AFS_SHUTDOWN; | |
159 | afs_termState = AFSOP_STOP_RXCALLBACK; | |
160 | rx_WakeupServerProcs(); | |
161 | while (afs_termState == AFSOP_STOP_RXCALLBACK) | |
162 | afs_osi_Sleep(&afs_termState); | |
163 | /* rx_ServerProc sets AFS_STOP_AFS */ | |
164 | ||
165 | while (afs_termState == AFSOP_STOP_AFS) { | |
166 | afs_osi_CancelWait(&AFS_WaitHandler); | |
167 | afs_osi_Sleep(&afs_termState); | |
168 | } | |
169 | /* afs_Daemon sets AFS_STOP_RXEVENT */ | |
170 | ||
171 | #if defined(RXK_LISTENER_ENV) | |
172 | while (afs_termState == AFSOP_STOP_RXEVENT) | |
173 | afs_osi_Sleep(&afs_termState); | |
174 | /* afs_rxevent_daemon sets AFSOP_STOP_RXK_LISTENER */ | |
175 | ||
176 | afs_osi_UnmaskRxkSignals(); | |
177 | osi_StopListener(); | |
178 | while (afs_termState == AFSOP_STOP_RXK_LISTENER) | |
179 | afs_osi_Sleep(&afs_termState); | |
180 | /* rxk_Listener sets AFSOP_STOP_COMPLETE */ | |
181 | #endif | |
182 | } | |
183 | ||
184 | static void | |
185 | token_conversion(char *buffer, int buf_size, int in) | |
186 | { | |
187 | struct ClearToken *ticket; | |
188 | afs_int32 *lptr, n; | |
189 | ||
190 | /* secret ticket */ | |
191 | if (buf_size < 4) return; | |
192 | lptr = (afs_int32 *)buffer; | |
193 | buffer += 4; buf_size -= 4; | |
194 | if (in) { | |
195 | *lptr = ntohl(*lptr); | |
196 | n = *lptr; | |
197 | } else { | |
198 | n = *lptr; | |
199 | *lptr = htonl(*lptr); | |
200 | } | |
201 | if (n < 0 || buf_size < n) return; | |
202 | buffer += n; buf_size -= n; | |
203 | ||
204 | /* clear token */ | |
205 | if (buf_size < 4) return; | |
206 | lptr = (afs_int32 *)buffer; | |
207 | buffer += 4; buf_size -= 4; | |
208 | if (in) { | |
209 | *lptr = ntohl(*lptr); | |
210 | n = *lptr; | |
211 | } else { | |
212 | n = *lptr; | |
213 | *lptr = htonl(*lptr); | |
214 | } | |
215 | if (n < 0 || buf_size < n) return; | |
216 | if (n >= sizeof(struct ClearToken)) { | |
217 | ticket = (struct ClearToken *)buffer; | |
218 | if (in) { | |
219 | ticket->AuthHandle = ntohl(ticket->AuthHandle); | |
220 | ticket->ViceId = ntohl(ticket->ViceId); | |
221 | ticket->BeginTimestamp = ntohl(ticket->BeginTimestamp); | |
222 | ticket->EndTimestamp = ntohl(ticket->EndTimestamp); | |
223 | } else { | |
224 | ticket->AuthHandle = htonl(ticket->AuthHandle); | |
225 | ticket->ViceId = htonl(ticket->ViceId); | |
226 | ticket->BeginTimestamp = htonl(ticket->BeginTimestamp); | |
227 | ticket->EndTimestamp = htonl(ticket->EndTimestamp); | |
228 | } | |
229 | } | |
230 | buffer += n; buf_size -= n; | |
231 | ||
232 | /* primary flag */ | |
233 | if (buf_size < 4) return; | |
234 | lptr = (afs_int32 *)buffer; | |
235 | if (in) { | |
236 | *lptr = ntohl(*lptr); | |
237 | } else { | |
238 | *lptr = htonl((*lptr) & ~0x8000); | |
239 | } | |
240 | return; | |
241 | } | |
242 | ||
243 | static void | |
244 | FetchVolumeStatus_conversion(char *buffer, int buf_size, int in) | |
245 | { | |
246 | AFSFetchVolumeStatus *status = (AFSFetchVolumeStatus *)buffer; | |
247 | ||
248 | if (buf_size < sizeof(AFSFetchVolumeStatus)) | |
249 | return; | |
250 | if (in) { | |
251 | status->Vid = ntohl(status->Vid); | |
252 | status->ParentId = ntohl(status->ParentId); | |
253 | status->Type = ntohl(status->Type); | |
254 | status->MinQuota = ntohl(status->MinQuota); | |
255 | status->MaxQuota = ntohl(status->MaxQuota); | |
256 | status->BlocksInUse = ntohl(status->BlocksInUse); | |
257 | status->PartBlocksAvail = ntohl(status->PartBlocksAvail); | |
258 | status->PartMaxBlocks = ntohl(status->PartMaxBlocks); | |
259 | } else { | |
260 | status->Vid = htonl(status->Vid); | |
261 | status->ParentId = htonl(status->ParentId); | |
262 | status->Type = htonl(status->Type); | |
263 | status->MinQuota = htonl(status->MinQuota); | |
264 | status->MaxQuota = htonl(status->MaxQuota); | |
265 | status->BlocksInUse = htonl(status->BlocksInUse); | |
266 | status->PartBlocksAvail = htonl(status->PartBlocksAvail); | |
267 | status->PartMaxBlocks = htonl(status->PartMaxBlocks); | |
268 | } | |
269 | } | |
270 | ||
271 | static void | |
272 | inparam_conversion(int cmd, char *buffer, int buf_size, int in) | |
273 | { | |
274 | afs_int32 *lptr = (afs_int32 *)buffer; | |
275 | ||
276 | switch (cmd & 0xffff) { | |
277 | case (0x5600 | 3): /* VIOCSETTOK */ | |
278 | token_conversion(buffer, buf_size, in); | |
279 | return; | |
280 | ||
281 | case (0x5600 | 5): /* VIOCSETVOLSTAT */ | |
282 | FetchVolumeStatus_conversion(buffer, buf_size, in); | |
283 | return; | |
284 | ||
285 | case (0x5600 | 8): /* VIOCGETTOK */ | |
286 | case (0x5600 | 10): /* VIOCCKSERV */ | |
287 | case (0x5600 | 20): /* VIOCACCESS */ | |
288 | case (0x5600 | 24): /* VIOCSETCACHESIZE */ | |
289 | case (0x5600 | 27): /* VIOCGETCELL */ | |
290 | case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */ | |
291 | case (0x5600 | 34): /* VIOC_VENUSLOG */ | |
292 | case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ | |
293 | case (0x5600 | 39): /* VIOC_EXPORTAFS */ | |
294 | /* one 32-bit integer */ | |
295 | if (buf_size >= 4) { | |
296 | if (in) lptr[0] = ntohl(lptr[0]); | |
297 | else lptr[0] = htonl(lptr[0]); | |
298 | } | |
299 | return; | |
300 | ||
301 | case (0x5600 | 36): /* VIOCSETCELLSTATUS */ | |
302 | /* two 32-bit integers */ | |
303 | if (buf_size >= 4) { | |
304 | if (in) lptr[0] = ntohl(lptr[0]); | |
305 | else lptr[0] = htonl(lptr[0]); | |
306 | } | |
307 | if (buf_size >= 8) { | |
308 | if (in) lptr[1] = ntohl(lptr[1]); | |
309 | else lptr[1] = htonl(lptr[1]); | |
310 | } | |
311 | return; | |
312 | } | |
313 | } | |
314 | ||
315 | static void | |
316 | outparam_conversion(int cmd, char *buffer, int buf_size, int in) | |
317 | { | |
318 | afs_int32 *lptr = (afs_int32 *)buffer; | |
319 | int i; | |
320 | ||
321 | switch (cmd & 0xffff) { | |
322 | case (0x5600 | 4): /* VIOCGETVOLSTAT */ | |
323 | case (0x5600 | 5): /* VIOCSETVOLSTAT */ | |
324 | FetchVolumeStatus_conversion(buffer, buf_size, in); | |
325 | return; | |
326 | ||
327 | case (0x5600 | 8): /* VIOCGETTOK */ | |
328 | token_conversion(buffer, buf_size, in); | |
329 | return; | |
330 | ||
331 | case (0x5600 | 12): /* VIOCCKCONN */ | |
332 | case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */ | |
333 | case (0x5600 | 34): /* VIOC_VENUSLOG */ | |
334 | case (0x5600 | 35): /* VIOC_GETCELLSTATUS */ | |
335 | case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ | |
336 | case (0x5600 | 39): /* VIOC_EXPORTAFS */ | |
337 | /* one 32-bit integer */ | |
338 | if (buf_size >= 4) { | |
339 | if (in) lptr[0] = ntohl(lptr[0]); | |
340 | else lptr[0] = htonl(lptr[0]); | |
341 | } | |
342 | return; | |
343 | ||
344 | case (0x5600 | 40): /* VIOCGETCACHEPARMS */ | |
345 | /* sixteen 32-bit integers */ | |
346 | for (i = 0; i < 16 && buf_size >= 4; i++) { | |
347 | if (in) lptr[i] = ntohl(lptr[i]); | |
348 | else lptr[i] = htonl(lptr[i]); | |
349 | buf_size -= 4; | |
350 | } | |
351 | return; | |
352 | } | |
353 | } | |
354 | ||
355 | ||
356 | /* called with the GLOCK held */ | |
357 | int | |
358 | afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow) | |
359 | { | |
360 | cred_t *credp = crref(); /* don't free until done! */ | |
361 | struct afs_ioctl data; | |
362 | struct clientcred ccred; | |
363 | struct rmtbulk idata, odata; | |
364 | short in_size, out_size; | |
365 | afs_int32 code = 0, pag, err; | |
366 | gid_t g0, g1; | |
367 | char *abspath, *pathbuf = 0; | |
368 | ||
369 | AFS_STATCNT(afs_syscall_pioctl); | |
370 | if (follow) | |
371 | follow = 1; /* compat. with old venus */ | |
372 | code = copyin_afs_ioctl(cmarg, &data); | |
373 | if (code) goto out; | |
374 | ||
375 | if ((com & 0xff) == 90) { | |
376 | /* PSetClientContext, in any space */ | |
377 | code = EINVAL; | |
378 | goto out; | |
379 | } | |
380 | ||
381 | /* Special handling for a few pioctls */ | |
382 | switch (com & 0xffff) { | |
383 | case (0x5600 | 3): /* VIOCSETTOK */ | |
384 | code = afspag_PSetTokens(data.in, data.in_size, &credp); | |
385 | if (code) goto out; | |
386 | break; | |
387 | ||
388 | case (0x5600 | 9): /* VIOCUNLOG */ | |
389 | case (0x5600 | 21): /* VIOCUNPAG */ | |
390 | code = afspag_PUnlog(data.in, data.in_size, &credp); | |
391 | if (code) goto out; | |
392 | break; | |
393 | ||
394 | case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ | |
395 | code = afspag_PSetSysName(data.in, data.in_size, &credp); | |
396 | if (code) goto out; | |
397 | break; | |
398 | } | |
399 | ||
400 | /* Set up credentials */ | |
401 | memset(&ccred, 0, sizeof(ccred)); | |
402 | pag = PagInCred(credp); | |
403 | ccred.uid = afs_cr_uid(credp); | |
404 | if (pag != NOPAG) { | |
405 | afs_get_groups_from_pag(pag, &g0, &g1); | |
406 | ccred.group0 = g0; | |
407 | ccred.group1 = g1; | |
408 | } | |
409 | ||
410 | /* | |
411 | * Copy the path and convert to absolute, if one was given. | |
412 | * NB: We can only use osI_AllocLargeSpace here as long as | |
413 | * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ. | |
414 | */ | |
415 | if (path) { | |
416 | pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN); | |
417 | if (!pathbuf) { | |
418 | code = ENOMEM; | |
419 | goto out; | |
420 | } | |
421 | code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath); | |
422 | if (code) | |
423 | goto out_path; | |
424 | } else { | |
425 | abspath = NIL_PATHP; | |
426 | } | |
427 | ||
428 | /* Allocate, copy, and convert incoming data */ | |
429 | idata.rmtbulk_len = in_size = data.in_size; | |
430 | if (in_size < 0 || in_size > MAXBUFFERLEN) { | |
431 | code = EINVAL; | |
432 | goto out_path; | |
433 | } | |
434 | if (in_size > AFS_LRALLOCSIZ) | |
435 | idata.rmtbulk_val = osi_Alloc(in_size); | |
436 | else | |
437 | idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); | |
438 | if (!idata.rmtbulk_val) { | |
439 | code = ENOMEM; | |
440 | goto out_path; | |
441 | } | |
442 | if (in_size) { | |
443 | AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code); | |
444 | if (code) | |
445 | goto out_idata; | |
446 | inparam_conversion(com, idata.rmtbulk_val, in_size, 0); | |
447 | } | |
448 | ||
449 | /* Allocate space for outgoing data */ | |
450 | odata.rmtbulk_len = out_size = data.out_size; | |
451 | if (out_size < 0 || out_size > MAXBUFFERLEN) { | |
452 | code = EINVAL; | |
453 | goto out_idata; | |
454 | } | |
455 | if (out_size > AFS_LRALLOCSIZ) | |
456 | odata.rmtbulk_val = osi_Alloc(out_size); | |
457 | else | |
458 | odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); | |
459 | if (!odata.rmtbulk_val) { | |
460 | code = ENOMEM; | |
461 | goto out_idata; | |
462 | } | |
463 | ||
464 | AFS_GUNLOCK(); | |
465 | code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow, | |
466 | &idata, &odata, &err); | |
467 | AFS_GLOCK(); | |
468 | if (code) | |
469 | goto out_odata; | |
470 | ||
471 | /* Convert and copy out the result */ | |
472 | if (odata.rmtbulk_len > out_size) { | |
473 | code = E2BIG; | |
474 | goto out_odata; | |
475 | } | |
476 | if (odata.rmtbulk_len) { | |
477 | outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1); | |
478 | AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code); | |
479 | } | |
480 | if (!code) | |
481 | code = err; | |
482 | ||
483 | out_odata: | |
484 | if (out_size > AFS_LRALLOCSIZ) | |
485 | osi_Free(odata.rmtbulk_val, out_size); | |
486 | else | |
487 | osi_FreeLargeSpace(odata.rmtbulk_val); | |
488 | ||
489 | out_idata: | |
490 | if (in_size > AFS_LRALLOCSIZ) | |
491 | osi_Free(idata.rmtbulk_val, in_size); | |
492 | else | |
493 | osi_FreeLargeSpace(idata.rmtbulk_val); | |
494 | ||
495 | out_path: | |
496 | if (path) | |
497 | osi_FreeLargeSpace(pathbuf); | |
498 | ||
499 | out: | |
500 | crfree(credp); | |
501 | #if defined(KERNEL_HAVE_UERROR) | |
502 | if (!getuerror()) | |
503 | setuerror(code); | |
504 | return (getuerror()); | |
505 | #else | |
506 | return (code); | |
507 | #endif | |
508 | } | |
509 | ||
510 | ||
511 | int | |
512 | afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6) | |
513 | long parm, parm2, parm3, parm4, parm5, parm6; | |
514 | { | |
515 | /* Superusers may shut us down, such as with afsd -shutdown. */ | |
516 | if (parm == AFSOP_SHUTDOWN && afs_suser(NULL)) | |
517 | { | |
518 | AFS_GLOCK(); | |
519 | afspag_Shutdown(); | |
520 | AFS_GUNLOCK(); | |
521 | return 0; | |
522 | } | |
523 | ||
524 | /* otherwise, we don't support afs_syscall_call, period */ | |
525 | #if defined(KERNEL_HAVE_UERROR) | |
526 | setuerror(EPERM); | |
527 | #endif | |
528 | return EPERM; | |
529 | } |