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 | /* this is a version of klog which attempts to authenticate many times | |
11 | * in a loop. It is a test program, and isn't really intended for general | |
12 | * use. | |
13 | */ | |
14 | ||
15 | /* These two needed for rxgen output to work */ | |
16 | ||
17 | #include <afsconfig.h> | |
18 | #include <afs/param.h> | |
19 | ||
20 | ||
21 | #include <afs/stds.h> | |
22 | #include <sys/types.h> | |
23 | #include <rx/xdr.h> | |
24 | ||
25 | #include <lock.h> | |
26 | #include <ubik.h> | |
27 | ||
28 | #include <stdio.h> | |
29 | #include <pwd.h> | |
30 | #include <afs/com_err.h> | |
31 | #include <afs/cellconfig.h> | |
32 | #include <afs/cmd.h> | |
33 | #include "kauth.h" | |
34 | #include "kautils.h" | |
35 | ||
36 | /* Current Usage: | |
37 | mutliklog [principal [password]] [-t] [-c cellname] [-servers <hostlist>] [-number n] | |
38 | ||
39 | where: | |
40 | principal is of the form 'name' or 'name@cell' which provides the | |
41 | cellname. See the -c option below. | |
42 | password is the user's password. This form is NOT recommended for | |
43 | interactive users. | |
44 | -t advises klog to write a Kerberos style ticket file in /tmp. | |
45 | -c identifies cellname as the cell in which authentication is to take | |
46 | place. | |
47 | -servers allows the explicit specification of the hosts providing | |
48 | authentication services for the cell being used for authentication. | |
49 | This is a debugging option and will disappear. | |
50 | -repeat is the number of times to iterate over the authentication | |
51 | */ | |
52 | ||
53 | static int CommandProc(struct cmd_syndesc *, void *); | |
54 | ||
55 | static int zero_argc; | |
56 | static char **zero_argv; | |
57 | ||
58 | int | |
59 | osi_audit() | |
60 | { | |
61 | /* this sucks but it works for now. | |
62 | */ | |
63 | return 0; | |
64 | } | |
65 | ||
66 | main(argc, argv) | |
67 | int argc; | |
68 | char *argv[]; | |
69 | { | |
70 | struct cmd_syndesc *ts; | |
71 | long code; | |
72 | ||
73 | zero_argc = argc; | |
74 | zero_argv = argv; | |
75 | ||
76 | ts = cmd_CreateSyntax(NULL, CommandProc, NULL, 0, | |
77 | "obtain Kerberos authentication"); | |
78 | ||
79 | #define aXFLAG 0 | |
80 | #define aPRINCIPAL 1 | |
81 | #define aPASSWORD 2 | |
82 | #define aTMP 3 | |
83 | #define aCELL 4 | |
84 | #define aSERVERS 5 | |
85 | #define aPIPE 6 | |
86 | #define aSILENT 7 | |
87 | #define aLIFETIME 8 | |
88 | #define aREPCOUNT 9 | |
89 | ||
90 | cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)"); | |
91 | cmd_Seek(ts, aPRINCIPAL); | |
92 | cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name"); | |
93 | cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password"); | |
94 | cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL, | |
95 | "write Kerberos-style ticket file in /tmp"); | |
96 | cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name"); | |
97 | cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, | |
98 | "explicit list of servers"); | |
99 | cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL, | |
100 | "read password from stdin"); | |
101 | cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation"); | |
102 | cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, | |
103 | "ticket lifetime in hh[:mm[:ss]]"); | |
104 | cmd_AddParm(ts, "-repeat", CMD_SINGLE, CMD_OPTIONAL, | |
105 | "number of times to repeat authentication"); | |
106 | ||
107 | code = cmd_Dispatch(argc, argv); | |
108 | exit(code); | |
109 | } | |
110 | ||
111 | extern struct passwd *getpwuid(); | |
112 | ||
113 | static char * | |
114 | getpipepass() | |
115 | { | |
116 | static char gpbuf[BUFSIZ]; | |
117 | /* read a password from stdin, stop on \n or eof */ | |
118 | int i, tc; | |
119 | memset(gpbuf, 0, sizeof(gpbuf)); | |
120 | for (i = 0; i < (sizeof(gpbuf) - 1); i++) { | |
121 | tc = fgetc(stdin); | |
122 | if (tc == '\n' || tc == EOF) | |
123 | break; | |
124 | gpbuf[i] = tc; | |
125 | } | |
126 | return gpbuf; | |
127 | } | |
128 | ||
129 | static int | |
130 | CommandProc(struct cmd_syndesc *as, void *arock) | |
131 | { | |
132 | char name[MAXKTCNAMELEN]; | |
133 | char instance[MAXKTCNAMELEN]; | |
134 | char cell[MAXKTCREALMLEN]; | |
135 | char realm[MAXKTCREALMLEN]; | |
136 | long serverList[MAXSERVERS]; | |
137 | char *lcell; /* local cellname */ | |
138 | char lrealm[MAXKTCREALMLEN]; /* uppercase copy of local cellname */ | |
139 | int code; | |
140 | int i; | |
141 | Date lifetime; /* requested ticket lifetime */ | |
142 | ||
143 | struct passwd pwent; | |
144 | struct passwd *pw = &pwent; | |
145 | struct passwd *lclpw = &pwent; | |
146 | char passwd[BUFSIZ]; | |
147 | ||
148 | static char rn[] = "klog"; /*Routine name */ | |
149 | static int Pipe = 0; /* reading from a pipe */ | |
150 | static int Silent = 0; /* Don't want error messages */ | |
151 | static int reps = 1; | |
152 | static long storecode = 0; /* hold a non-zero error code, if any */ | |
153 | ||
154 | int explicit; /* servers specified explicitly */ | |
155 | int local; /* explicit cell is same a local one */ | |
156 | int foundPassword = 0; /*Not yet, anyway */ | |
157 | int foundExplicitCell = 0; /*Not yet, anyway */ | |
158 | int writeTicketFile = 0; /* write ticket file to /tmp */ | |
159 | long password_expires = -1; | |
160 | ||
161 | char *reason; /* string describing errors */ | |
162 | ||
163 | /* blow away command line arguments */ | |
164 | for (i = 1; i < zero_argc; i++) | |
165 | memset(zero_argv[i], 0, strlen(zero_argv[i])); | |
166 | zero_argc = 0; | |
167 | ||
168 | /* first determine quiet flag based on -silent switch */ | |
169 | Silent = (as->parms[aSILENT].items ? 1 : 0); | |
170 | Pipe = (as->parms[aPIPE].items ? 1 : 0); | |
171 | ||
172 | code = ka_Init(0); | |
173 | if (code || !(lcell = ka_LocalCell())) { | |
174 | nocell: | |
175 | if (!Silent) | |
176 | afs_com_err(rn, code, "Can't get local cell name!"); | |
177 | exit(code); | |
178 | } | |
179 | if (code = ka_CellToRealm(lcell, lrealm, 0)) | |
180 | goto nocell; | |
181 | ||
182 | strcpy(instance, ""); | |
183 | ||
184 | /* Parse our arguments. */ | |
185 | ||
186 | if (as->parms[aTMP].items) { | |
187 | writeTicketFile = 1; | |
188 | } | |
189 | ||
190 | if (as->parms[aCELL].items) { | |
191 | /* | |
192 | * cell name explicitly mentioned; take it in if no other cell name | |
193 | * has already been specified and if the name actually appears. If | |
194 | * the given cell name differs from our own, we don't do a lookup. | |
195 | */ | |
196 | foundExplicitCell = 1; | |
197 | strncpy(realm, as->parms[aCELL].items->data, sizeof(realm)); | |
198 | } | |
199 | ||
200 | if (as->parms[aSERVERS].items) { | |
201 | /* explicit server list */ | |
202 | int i; | |
203 | struct cmd_item *ip; | |
204 | char *ap[MAXSERVERS + 2]; | |
205 | ||
206 | for (ip = as->parms[aSERVERS].items, i = 2; ip; ip = ip->next, i++) | |
207 | ap[i] = ip->data; | |
208 | ap[0] = ""; | |
209 | ap[1] = "-servers"; | |
210 | code = ubik_ParseClientList(i, ap, serverList); | |
211 | if (code) { | |
212 | if (!Silent) { | |
213 | afs_com_err(rn, code, "could not parse server list"); | |
214 | } | |
215 | return code; | |
216 | } | |
217 | explicit = 1; | |
218 | } else | |
219 | explicit = 0; | |
220 | ||
221 | if (as->parms[aPRINCIPAL].items) { | |
222 | ka_ParseLoginName(as->parms[aPRINCIPAL].items->data, name, instance, | |
223 | cell); | |
224 | if (strlen(instance) > 0) | |
225 | if (!Silent) { | |
226 | fprintf(stderr, | |
227 | "Non-null instance (%s) may cause strange behavior.\n", | |
228 | instance); | |
229 | } | |
230 | if (strlen(cell) > 0) { | |
231 | if (foundExplicitCell) { | |
232 | if (!Silent) { | |
233 | fprintf(stderr, | |
234 | "%s: May not specify an explicit cell twice.\n", | |
235 | rn); | |
236 | } | |
237 | return -1; | |
238 | } | |
239 | foundExplicitCell = 1; | |
240 | strncpy(realm, cell, sizeof(realm)); | |
241 | } | |
242 | lclpw->pw_name = name; | |
243 | } else { | |
244 | /* No explicit name provided: use Unix uid. */ | |
245 | pw = getpwuid(getuid()); | |
246 | if (pw == 0) { | |
247 | if (!Silent) { | |
248 | fprintf(stderr, | |
249 | "Can't figure out your name in local cell %s from your user id.\n", | |
250 | lcell); | |
251 | fprintf(stderr, "Try providing the user name.\n"); | |
252 | } | |
253 | exit(1); | |
254 | } | |
255 | lclpw = pw; | |
256 | } | |
257 | ||
258 | if (as->parms[aPASSWORD].items) { | |
259 | /* | |
260 | * Current argument is the desired password string. Remember it in | |
261 | * our local buffer, and zero out the argument string - anyone can | |
262 | * see it there with ps! | |
263 | */ | |
264 | foundPassword = 1; | |
265 | strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd)); | |
266 | memset(as->parms[aPASSWORD].items->data, 0, | |
267 | strlen(as->parms[aPASSWORD].items->data)); | |
268 | } | |
269 | ||
270 | if (as->parms[aLIFETIME].items) { | |
271 | char *life = as->parms[aLIFETIME].items->data; | |
272 | char *sp; /* string ptr to rest of life */ | |
273 | lifetime = 3600 * strtol(life, &sp, 0); /* hours */ | |
274 | if (sp == life) { | |
275 | bad_lifetime: | |
276 | if (!Silent) | |
277 | fprintf(stderr, "%s: translating '%s' to lifetime\n", rn, | |
278 | life); | |
279 | return -1; | |
280 | } | |
281 | if (*sp == ':') { | |
282 | life = sp + 1; /* skip the colon */ | |
283 | lifetime += 60 * strtol(life, &sp, 0); /* minutes */ | |
284 | if (sp == life) | |
285 | goto bad_lifetime; | |
286 | if (*sp == ':') { | |
287 | life = sp + 1; | |
288 | lifetime += strtol(life, &sp, 0); /* seconds */ | |
289 | if (sp == life) | |
290 | goto bad_lifetime; | |
291 | if (*sp) | |
292 | goto bad_lifetime; | |
293 | } else if (*sp) | |
294 | goto bad_lifetime; | |
295 | } else if (*sp) | |
296 | goto bad_lifetime; | |
297 | if (lifetime > MAXKTCTICKETLIFETIME) { | |
298 | if (!Silent) | |
299 | fprintf(stderr, | |
300 | "%s: a lifetime of %.2f hours is too long, must be less than %d.\n", | |
301 | rn, (double)lifetime / 3600.0, | |
302 | MAXKTCTICKETLIFETIME / 3600); | |
303 | exit(1); | |
304 | } | |
305 | } else | |
306 | lifetime = 0; | |
307 | ||
308 | if (as->parms[aREPCOUNT].items) { | |
309 | reps = atoi(as->parms[aREPCOUNT].items->data); | |
310 | } | |
311 | ||
312 | if (!foundExplicitCell) | |
313 | strcpy(realm, lcell); | |
314 | if (code = ka_CellToRealm(realm, realm, &local)) { | |
315 | if (!Silent) | |
316 | afs_com_err(rn, code, "Can't convert cell to realm"); | |
317 | exit(code); | |
318 | } | |
319 | ||
320 | /* Get the password if it wasn't provided. */ | |
321 | if (!foundPassword) { | |
322 | if (Pipe) { | |
323 | strncpy(passwd, getpipepass(), sizeof(passwd)); | |
324 | } else { | |
325 | if (ka_UserReadPassword | |
326 | ("Password:", passwd, sizeof(passwd), &reason)) { | |
327 | fprintf(stderr, "Unable to login because %s.\n", reason); | |
328 | exit(1); | |
329 | } | |
330 | } | |
331 | } | |
332 | ||
333 | if (explicit) | |
334 | ka_ExplicitCell(realm, serverList); | |
335 | ||
336 | /* we really want this to fail repeatedly, though we only check one return | |
337 | * code. I hope it's representative... | |
338 | */ | |
339 | for (i = 0; i < reps; i++) { | |
340 | code = | |
341 | ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, pw->pw_name, | |
342 | instance, realm, passwd, lifetime, | |
343 | &password_expires, 0, &reason); | |
344 | if (code) | |
345 | storecode = code; | |
346 | } | |
347 | code = storecode; | |
348 | ||
349 | memset(passwd, 0, sizeof(passwd)); | |
350 | if (code) { | |
351 | if (!Silent) { | |
352 | fprintf(stderr, "Unable to authenticate to AFS because %s.\n", | |
353 | reason); | |
354 | } | |
355 | exit(code); | |
356 | } | |
357 | ||
358 | if (writeTicketFile) { | |
359 | code = krb_write_ticket_file(realm); | |
360 | if (!Silent) { | |
361 | if (code) | |
362 | afs_com_err(rn, code, "writing Kerberos ticket file"); | |
363 | else | |
364 | fprintf(stderr, "Wrote ticket file to /tmp\n"); | |
365 | } | |
366 | } | |
367 | #ifdef DEBUGEXPIRES | |
368 | if (password_expires >= 0) { | |
369 | printf("password expires at %ld\n", password_expires); | |
370 | } | |
371 | #endif /* DEBUGEXPIRES */ | |
372 | ||
373 | exit(0); | |
374 | } |