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