linux-and-64bit-cleanup-20050710
[openafs.git] / src / kauth / knfs.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 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 RCSID
18     ("$Header$");
19
20 #include <stdio.h>
21 #include <afs/stds.h>
22 #include <sys/types.h>
23 #include <ctype.h>
24 #include <sys/stat.h>
25 #include <signal.h>
26 #include <time.h>
27 #include <netdb.h>
28 #include <errno.h>
29 #include <sys/ioctl.h>
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #else
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h>
35 #endif
36 #endif
37 #include <afs/vice.h>
38 #include <afs/cmd.h>
39 #include <afs/auth.h>
40 #include <afs/afsutil.h>
41
42
43 extern struct cmd_syndesc *cmd_CreateSyntax();
44
45 /*
46 Modifications:
47
48 29 Oct 1992 Patch GetTokens to print something reasonable when there are no tokens.
49
50 */
51
52 /* this is a structure used to communicate with the afs cache mgr, but is
53  * otherwise irrelevant, or worse.
54  */
55 struct ClearToken {
56     afs_int32 AuthHandle;
57     char HandShakeKey[8];
58     afs_int32 ViceId;
59     afs_int32 BeginTimestamp;
60     afs_int32 EndTimestamp;
61 };
62
63
64 static
65 SetSysname(ahost, auid, sysname)
66      afs_int32 ahost;
67      afs_int32 auid;
68      char *sysname;
69 {
70     afs_int32 code;
71     afs_int32 pheader[6];
72     char space[1200], *tp;
73     struct ViceIoctl blob;
74     afs_int32 setp = 1;
75
76     /* otherwise we've got the token, now prepare to build the pioctl args */
77     pheader[0] = ahost;
78     pheader[1] = auid;
79     pheader[2] = 0;             /* group low */
80     pheader[3] = 0;             /* group high */
81     pheader[4] = 38 /*VIOC_AFS_SYSNAME */ ;     /* sysname pioctl index */
82     pheader[5] = 1;             /* NFS protocol exporter # */
83
84     /* copy stuff in */
85     memcpy(space, pheader, sizeof(pheader));
86     tp = space + sizeof(pheader);
87
88     /* finally setup the pioctl call's parameters */
89     blob.in_size = sizeof(pheader);
90     blob.in = space;
91     blob.out_size = 0;
92     blob.out = NULL;
93     memcpy(tp, &setp, sizeof(afs_int32));
94     tp += sizeof(afs_int32);
95     strcpy(tp, sysname);
96     blob.in_size += sizeof(afs_int32) + strlen(sysname) + 1;
97     tp += strlen(sysname);
98     *(tp++) = '\0';
99     code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
100     if (code) {
101         code = errno;
102     }
103     return code;
104 }
105
106
107 static
108 GetTokens(ahost, auid)
109      afs_int32 ahost;
110      afs_int32 auid;
111 {
112     struct ViceIoctl iob;
113     afs_int32 pheader[6];
114     char tbuffer[1024];
115     register afs_int32 code;
116     int index, newIndex;
117     char *stp;                  /* secret token ptr */
118     struct ClearToken ct;
119     register char *tp;
120     afs_int32 temp, gotit = 0;
121     int maxLen;                 /* biggest ticket we can copy */
122     int tktLen;                 /* server ticket length */
123     time_t tokenExpireTime;
124     char UserName[16];
125     struct ktc_token token;
126     struct ktc_principal clientName;
127     time_t current_time;
128     char *expireString;
129
130     current_time = time(0);
131
132     /* otherwise we've got the token, now prepare to build the pioctl args */
133     pheader[0] = ahost;
134     pheader[1] = auid;
135     pheader[2] = 0;             /* group low */
136     pheader[3] = 0;             /* group high */
137     pheader[4] = 8;             /* gettoken pioctl index */
138     pheader[5] = 1;             /* NFS protocol exporter # */
139
140     for (index = 0; index < 200; index++) {     /* sanity check in case pioctl fails */
141         code = ktc_ListTokens(index, &newIndex, &clientName);
142         if (code) {
143             if (code == KTC_NOENT) {
144                 /* all done */
145                 if (!gotit)
146                     printf("knfs: there are no tokens here.\n");
147                 code = 0;
148             }
149             break;              /* done, but failed */
150         }
151         if (strcmp(clientName.name, "afs") != 0)
152             continue;           /* wrong ticket service */
153
154         /* copy stuff in */
155         memcpy(tbuffer, pheader, sizeof(pheader));
156         tp = tbuffer + sizeof(pheader);
157         memcpy(tp, &index, sizeof(afs_int32));
158         tp += sizeof(afs_int32);
159         iob.in = tbuffer;
160         iob.in_size = sizeof(afs_int32) + sizeof(pheader);
161         iob.out = tbuffer;
162         iob.out_size = sizeof(tbuffer);
163         code = pioctl(NULL, _VICEIOCTL(99), &iob, 0);
164         if (code < 0 && errno == EDOM)
165             return KTC_NOENT;
166         else if (code == 0) {
167             /* check to see if this is the right cell/realm */
168             tp = tbuffer;
169             memcpy(&temp, tp, sizeof(afs_int32));       /* get size of secret token */
170             tktLen = temp;      /* remember size of ticket */
171             tp += sizeof(afs_int32);
172             stp = tp;           /* remember where ticket is, for later */
173             tp += temp;         /* skip ticket for now */
174             memcpy(&temp, tp, sizeof(afs_int32));       /* get size of clear token */
175             if (temp != sizeof(struct ClearToken))
176                 return KTC_ERROR;
177             tp += sizeof(afs_int32);    /* skip length */
178             memcpy(&ct, tp, temp);      /* copy token for later use */
179             tp += temp;         /* skip clear token itself */
180             tp += sizeof(afs_int32);    /* skip primary flag */
181             /* tp now points to the cell name */
182             if (strcmp(tp, clientName.cell) == 0) {
183                 /* closing in now, we've got the right cell */
184                 gotit = 1;
185                 maxLen =
186                     sizeof(token) - sizeof(struct ktc_token) +
187                     MAXKTCTICKETLEN;
188                 if (maxLen < tktLen)
189                     return KTC_TOOBIG;
190                 memcpy(token.ticket, stp, tktLen);
191                 token.startTime = ct.BeginTimestamp;
192                 token.endTime = ct.EndTimestamp;
193                 if (ct.AuthHandle == -1)
194                     ct.AuthHandle = 999;
195                 token.kvno = ct.AuthHandle;
196                 memcpy(&token.sessionKey, ct.HandShakeKey,
197                        sizeof(struct ktc_encryptionKey));
198                 token.ticketLen = tktLen;
199                 if ((token.kvno == 999) ||      /* old style bcrypt ticket */
200                     (ct.BeginTimestamp &&       /* new w/ prserver lookup */
201                      (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
202                     sprintf(clientName.name, "AFS ID %d", ct.ViceId);
203                     clientName.instance[0] = 0;
204                 } else {
205                     sprintf(clientName.name, "Unix UID %d", ct.ViceId);
206                     clientName.instance[0] = 0;
207                 }
208                 strcpy(clientName.cell, tp);
209
210                 tokenExpireTime = token.endTime;
211                 strcpy(UserName, clientName.name);
212                 if (clientName.instance[0] != 0) {
213                     strcat(UserName, ".");
214                     strcat(UserName, clientName.instance);
215                 }
216                 if (UserName[0] == 0)
217                     printf("Tokens");
218                 else if (strncmp(UserName, "AFS ID", 6) == 0) {
219                     printf("User's (%s) tokens", UserName);
220                 } else if (strncmp(UserName, "Unix UID", 8) == 0) {
221                     printf("Tokens");
222                 } else
223                     printf("User %s's tokens", UserName);
224                 printf(" for %s%s%s@%s ", clientName.name,
225                        clientName.instance[0] ? "." : "", clientName.instance,
226                        clientName.cell);
227                 if (tokenExpireTime <= current_time)
228                     printf("[>> Expired <<]\n");
229                 else {
230                     expireString = ctime(&tokenExpireTime);
231                     expireString += 4;  /*Move past the day of week */
232                     expireString[12] = '\0';
233                     printf("[Expires %s]\n", expireString);
234                 }
235
236             }
237         }
238     }
239     return code;
240 }
241
242
243 static
244 NFSUnlog(ahost, auid)
245      afs_int32 ahost;
246      afs_int32 auid;
247 {
248     afs_int32 code;
249     afs_int32 pheader[6];
250     char space[1200];
251     struct ViceIoctl blob;
252
253     /* otherwise we've got the token, now prepare to build the pioctl args */
254     pheader[0] = ahost;
255     pheader[1] = auid;
256     pheader[2] = 0;             /* group low */
257     pheader[3] = 0;             /* group high */
258     pheader[4] = 9;             /* unlog pioctl index */
259     pheader[5] = 1;             /* NFS protocol exporter # */
260
261     /* copy stuff in */
262     memcpy(space, pheader, sizeof(pheader));
263
264     /* finally setup the pioctl call's parameters */
265     blob.in_size = sizeof(pheader);
266     blob.in = space;
267     blob.out_size = 0;
268     blob.out = NULL;
269     code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
270     if (code) {
271         code = errno;
272     }
273     return code;
274 }
275
276 /* Copy the AFS service token into the kernel for a particular host and user */
277 static
278 NFSCopyToken(ahost, auid)
279      afs_int32 ahost;
280      afs_int32 auid;
281 {
282     struct ktc_principal client, server;
283     struct ktc_token theTicket;
284     afs_int32 code;
285     afs_int32 pheader[6];
286     char space[1200];
287     struct ClearToken ct;
288     afs_int32 index, newIndex;
289     afs_int32 temp;             /* for bcopy */
290     char *tp;
291     struct ViceIoctl blob;
292
293     for (index = 0;; index = newIndex) {
294         code = ktc_ListTokens(index, &newIndex, &server);
295         if (code) {
296             if (code == KTC_NOENT) {
297                 /* all done */
298                 code = 0;
299             }
300             break;              /* done, but failed */
301         }
302         if (strcmp(server.name, "afs") != 0)
303             continue;           /* wrong ticket service */
304         code = ktc_GetToken(&server, &theTicket, sizeof(theTicket), &client);
305         if (code)
306             return code;
307
308         /* otherwise we've got the token, now prepare to build the pioctl args */
309         pheader[0] = ahost;
310         pheader[1] = auid;
311         pheader[2] = 0;         /* group low */
312         pheader[3] = 0;         /* group high */
313         pheader[4] = 3;         /* set token pioctl index */
314         pheader[5] = 1;         /* NFS protocol exporter # */
315
316         /* copy in the header */
317         memcpy(space, pheader, sizeof(pheader));
318         tp = space + sizeof(pheader);
319         /* copy in the size of the encrypted part */
320         memcpy(tp, &theTicket.ticketLen, sizeof(afs_int32));
321         tp += sizeof(afs_int32);
322         /* copy in the ticket itself */
323         memcpy(tp, theTicket.ticket, theTicket.ticketLen);
324         tp += theTicket.ticketLen;
325         /* copy in "clear token"'s size */
326         temp = sizeof(struct ClearToken);
327         memcpy(tp, &temp, sizeof(afs_int32));
328         tp += sizeof(afs_int32);
329         /* create the clear token and copy *it* in */
330         ct.AuthHandle = theTicket.kvno; /* where we hide the key version # */
331         memcpy(ct.HandShakeKey, &theTicket.sessionKey,
332                sizeof(ct.HandShakeKey));
333
334         ct.ViceId = auid;
335         ct.BeginTimestamp = theTicket.startTime;
336         ct.EndTimestamp = theTicket.endTime;
337         memcpy(tp, &ct, sizeof(ct));
338         tp += sizeof(ct);
339         /* copy in obsolete primary flag */
340         temp = 0;
341         memcpy(tp, &temp, sizeof(afs_int32));
342         tp += sizeof(afs_int32);
343         /* copy in cell name, null terminated */
344         strcpy(tp, server.cell);
345         tp += strlen(server.cell) + 1;
346
347         /* finally setup the pioctl call's parameters */
348         blob.in_size = tp - space;
349         blob.in = space;
350         blob.out_size = 0;
351         blob.out = NULL;
352         code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
353         if (code) {
354             code = errno;
355             break;
356         }
357     }
358     return code;
359 }
360
361 static
362 cmdproc(as, arock)
363      register struct cmd_syndesc *as;
364      afs_int32 arock;
365 {
366     register struct hostent *the;
367     char *tp, *sysname = 0;
368     afs_int32 uid, addr;
369     register afs_int32 code;
370
371     the = (struct hostent *)
372         hostutil_GetHostByName(tp = as->parms[0].items->data);
373     if (!the) {
374         printf("knfs: unknown host '%s'.\n", tp);
375         return -1;
376     }
377     memcpy(&addr, the->h_addr, sizeof(afs_int32));
378     uid = -1;
379     if (as->parms[1].items) {
380         code = util_GetInt32(tp = as->parms[1].items->data, &uid);
381         if (code) {
382             printf("knfs: can't parse '%s' as a number (UID)\n", tp);
383             return code;
384         }
385     } else
386         uid = -1;               /* means wildcard: match any user on this host */
387
388     /*
389      * If not "-id" is passed then we use the getuid() id, unless it's root
390      * that is doing it in which case we only authenticate as "system:anyuser"
391      * as it's appropriate for root. (The cm handles conversions from 0 to
392      * "afs_nobody"!)
393      */
394     if (uid == -1) {
395         uid = getuid();
396     }
397
398     if (as->parms[2].items) {
399         sysname = as->parms[2].items->data;
400     }
401
402     if (as->parms[4].items) {
403         /* tokens specified */
404         code = GetTokens(addr, uid);
405         if (code) {
406             if (code == ENOEXEC)
407                 printf
408                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
409             else
410                 printf("knfs: failed to get tokens for uid %d (code %d)\n",
411                        uid, code);
412         }
413         return code;
414     }
415
416     /* finally, parsing is done, make the call */
417     if (as->parms[3].items) {
418         /* unlog specified */
419         code = NFSUnlog(addr, uid);
420         if (code) {
421             if (code == ENOEXEC)
422                 printf
423                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
424             else
425                 printf("knfs: failed to unlog (code %d)\n", code);
426         }
427     } else {
428         code = NFSCopyToken(addr, uid);
429         if (code) {
430             if (code == ENOEXEC)
431                 printf
432                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
433             else
434                 printf("knfs: failed to copy tokens (code %d)\n", code);
435         }
436         if (sysname) {
437             code = SetSysname(addr, uid, sysname);
438             if (code) {
439                 printf("knfs: failed to set client's @sys to %s (code %d)\n",
440                        sysname, code);
441             }
442         }
443     }
444     return code;
445 }
446
447 #include "AFS_component_version_number.c"
448
449 main(argc, argv)
450      int argc;
451      char **argv;
452 {
453     register struct cmd_syndesc *ts;
454     register afs_int32 code;
455
456 #ifdef  AFS_AIX32_ENV
457     /*
458      * The following signal action for AIX is necessary so that in case of a 
459      * crash (i.e. core is generated) we can include the user's data section 
460      * in the core dump. Unfortunately, by default, only a partial core is
461      * generated which, in many cases, isn't too useful.
462      */
463     struct sigaction nsa;
464
465     sigemptyset(&nsa.sa_mask);
466     nsa.sa_handler = SIG_DFL;
467     nsa.sa_flags = SA_FULLDUMP;
468     sigaction(SIGABRT, &nsa, NULL);
469     sigaction(SIGSEGV, &nsa, NULL);
470 #endif
471
472     ts = cmd_CreateSyntax(NULL, cmdproc, 0, "copy tickets for NFS");
473     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_REQUIRED, "host name");
474     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "user ID (decimal)");
475     cmd_AddParm(ts, "-sysname", CMD_SINGLE, CMD_OPTIONAL,
476                 "host's '@sys' value");
477     cmd_AddParm(ts, "-unlog", CMD_FLAG, CMD_OPTIONAL, "unlog remote user");
478     cmd_AddParm(ts, "-tokens", CMD_FLAG, CMD_OPTIONAL,
479                 "display all tokens for remote [host,id]");
480
481     code = cmd_Dispatch(argc, argv);
482     return code;
483 }