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