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