Bug Summary

File:kauth/kkids.c
Location:line 188, column 2
Description:Value stored to 'bp' is never read

Annotated Source Code

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/* These two needed for rxgen output to work */
15#include <afsconfig.h>
16#include <afs/param.h>
17#include <afs/stds.h>
18
19#include <roken.h>
20
21#ifdef AFS_NT40_ENV
22#include <afs/fs_utils.h>
23#else
24#include <afs/venus.h>
25#endif
26
27#include <rx/xdr.h>
28#include <afs/prs_fs.h>
29#include <afs/sys_prototypes.h>
30#include <afs/afs_consts.h>
31
32#include "kkids.h"
33
34#define MAXNAME100 100
35
36static int using_child = 0;
37static FILE *childin, *childout; /* file pointers on pipe to kpwvalid */
38
39/* this removes symlinks from the tail end of path names.
40 * PRECONDITION: name must be either absolute ('/something') or
41 * explictly relative to current directory ('./something')
42 */
43static int
44simplify_name(char *orig_name, char *true_name)
45{
46 struct stat statbuff;
47
48
49#ifdef AFS_NT40_ENV
50 if (stat(orig_name, &statbuff) < 0) {
51 *true_name = '\0';
52 return 0;
53 } else {
54 strcpy(true_name, orig_name);
55 return 1;
56 }
57#else /* !NT40 */
58 {
59 int link_chars_read;
60 char *last_component;
61 if (lstat(orig_name, &statbuff) < 0) {
62 /* if lstat fails, it's possible that it's transient, but
63 * unlikely. Let's hope it isn't, and continue... */
64 *true_name = '\0';
65 return 0;
66 }
67
68 /*
69 * The lstat succeeded. If the given file is a symlink, substitute
70 * the contents of the link for the file name.
71 */
72 if ((statbuff.st_mode & S_IFMT0170000) == S_IFLNK0120000) {
73 link_chars_read = readlink(orig_name, true_name, 1024);
74 if (link_chars_read <= 0) {
75 *true_name = '\0';
76 return 0;
77 }
78
79 true_name[link_chars_read++] = '\0';
80
81 /*
82 * If the symlink is an absolute pathname, we're fine. Otherwise, we
83 * have to create a full pathname using the original name and the
84 * relative symlink name. Find the rightmost slash in the original
85 * name (we know there is one) and splice in the symlink contents.
86 */
87 if (true_name[0] != '/') {
88 last_component = (char *)strrchr(orig_name, '/');
89 strcpy(++last_component, true_name);
90 strcpy(true_name, orig_name);
91 }
92 } else
93 strcpy(true_name, orig_name);
94
95 return 1; /* found it */
96 }
97#endif /* !NT40 */
98}
99
100
101 /* We find our own location by:
102 * 1. checking for an absolute or relative path name in argv[0]
103 * this is moderately system-dependant: argv[0] is just a convention.
104 * 2. successively checking each component of PATH, and concatenating argv[0]
105 * onto it, then stating the result.
106 * if it exists, it must be us, eh?
107 * NB there may be possible security implications involving
108 * symlinks; I think they are only relevant if the symlink points
109 * directly at kpasswd, not when it points at kpasswd's parent directory.
110 */
111static int
112find_me(char *arg, char *parent_dir)
113{
114 char *bp; /* basename pointer */
115 char *dp; /* dirname pointer */
116 char *pathelt, orig_name[1024], truename[1022];
117
118#define explicitname(a,b,c)( ((a) == '/') || ( ((a) == '.') && ( ((b) == '/') ||
( ((b) == '.') && ((c) == '/') ) ) ) )
\
119 ( ((a) == '/') || \
120 ( ((a) == '.') && \
121 ( ((b) == '/') || \
122 ( ((b) == '.') && ((c) == '/') ) \
123 ) \
124 ) \
125 )
126
127 if (strlen(arg) > 510) /* just give up */
128 return 0;
129
130 *parent_dir = '\0';
131 truename[0] = '\0';
132
133 if (explicitname(arg[0], arg[1], arg[2])( ((arg[0]) == '/') || ( ((arg[0]) == '.') && ( ((arg
[1]) == '/') || ( ((arg[1]) == '.') && ((arg[2]) == '/'
) ) ) ) )
) {
134 strcpy(orig_name, arg);
135 simplify_name(orig_name, truename);
136 } else {
137 bp = (char *)strrchr(arg, '/');
138 if (bp) {
139 orig_name[0] = '.';
140 orig_name[1] = '/';
141 strcpy(orig_name + 2, arg);
142 simplify_name(orig_name, truename);
143 }
144 }
145
146 if (!truename[0]) { /* didn't find it */
147 char path[2046];
148
149 dp = getenv("PATH");
150 if (!dp)
151 return 0;
152 strncpy(path, dp, 2045);
153
154 for (pathelt = strtok(path, ":"); pathelt;
155 pathelt = strtok(NULL((void *)0), ":")) {
156 strncpy(orig_name, pathelt, 510);
157
158 bp = orig_name + strlen(orig_name);
159 *bp = '/'; /* replace NUL with / */
160 strncpy(bp + 1, arg, 510);
161
162 if (simplify_name(orig_name, truename))
163 break;
164 }
165 }
166 if (!truename[0]) /* didn't find it */
167 return 0; /* give up */
168
169 /* DID FIND IT */
170 /*
171 * Find rightmost slash, if any.
172 */
173 bp = (char *)strrchr(truename, '/');
174 if (bp) {
175 /*
176 * Found it. Designate everything before it as the parent directory,
177 * everything after it as the final component.
178 */
179 strncpy(parent_dir, truename, bp - truename);
180 parent_dir[bp - truename] = 0;
181 bp++; /*Skip the slash */
182 } else {
183 /*
184 * No slash appears in the given file name. Set parent_dir to the current
185 * directory, and the last component as the given name.
186 */
187 strcpy(parent_dir, ".");
188 bp = truename;
Value stored to 'bp' is never read
189 }
190
191 return 1; /* found it */
192}
193
194#define SkipLine(str){ while (*str !='\n') str++; str++; } { while (*str !='\n') str++; str++; }
195
196/* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
197static int
198InAFS(char *apath)
199{
200 struct ViceIoctl blob;
201 afs_int32 code;
202 char space[AFS_PIOCTL_MAXSIZE2048];
203
204 blob.in_size = 0;
205 blob.out_size = AFS_PIOCTL_MAXSIZE2048;
206 blob.out = space;
207
208 code = pioctl(apath, VIOC_FILE_CELL_NAME((unsigned int) ((unsigned long) ((0x80000000) | (((sizeof(struct
ViceIoctl)) & ((1 << 13) - 1)) << 16) | ((('V'
)) << 8) | ((30)))))
, &blob, 1);
209 if (code) {
210 if ((errno(* __error()) == EINVAL22) || (errno(* __error()) == ENOENT2))
211 return 0;
212 }
213 return 1;
214}
215
216struct Acl {
217 int nplus;
218 int nminus;
219 struct AclEntry *pluslist;
220 struct AclEntry *minuslist;
221};
222
223struct AclEntry {
224 struct AclEntry *next;
225 char name[MAXNAME100];
226 afs_int32 rights;
227};
228
229static struct Acl *
230ParseAcl(char *astr)
231{
232 int nplus, nminus, i, trights;
233 char tname[MAXNAME100];
234 struct AclEntry *first, *last, *tl;
235 struct Acl *ta;
236 sscanf(astr, "%d", &nplus);
237 SkipLine(astr){ while (*astr !='\n') astr++; astr++; };
238 sscanf(astr, "%d", &nminus);
239 SkipLine(astr){ while (*astr !='\n') astr++; astr++; };
240
241 ta = (struct Acl *)malloc(sizeof(struct Acl));
242 ta->nplus = nplus;
243
244 last = 0;
245 first = 0;
246 for (i = 0; i < nplus; i++) {
247 sscanf(astr, "%100s %d", tname, &trights);
248 SkipLine(astr){ while (*astr !='\n') astr++; astr++; };
249 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
250 if (!first)
251 first = tl;
252 strcpy(tl->name, tname);
253 tl->rights = trights;
254 tl->next = 0;
255 if (last)
256 last->next = tl;
257 last = tl;
258 }
259 ta->pluslist = first;
260
261 return ta;
262}
263
264static char *
265safestrtok(char *str, char *tok)
266{
267 char *temp;
268
269 if (str)
270 return (strtok(str, tok));
271
272 temp = strtok(NULL((void *)0), tok);
273 if (temp)
274 *(temp - 1) = *tok;
275
276 return temp;
277
278}
279
280
281/* If it exists, we do some fussing about whether or not this
282 * is a reasonably secure path - not that it makes *much* difference, since
283 * there's not much point in being more secure than the kpasswd executable.
284 */
285/* 1. is this directory in AFS?
286 * 2. Is every component of the pathname secure
287 * (ie, only system:administrators have w or a rights)?
288 */
289static int
290is_secure(char *dir)
291{
292 char *temp;
293 struct ViceIoctl blob;
294 struct AclEntry *te;
295 char space[2046];
296 afs_int32 code;
297 struct Acl *ta;
298
299 if (!InAFS(dir)) /* final component *must* be in AFS */
300 return 0;
301
302#ifndef INSECURE
303 for (temp = safestrtok(dir, "/"); temp; temp = safestrtok(NULL((void *)0), "/")) {
304 /* strtok keeps sticking NUL in place of /, so we can look at
305 * ever-longer chunks of the path.
306 */
307 if (!InAFS(dir))
308 continue;
309
310 blob.out_size = AFS_PIOCTL_MAXSIZE2048;
311 blob.in_size = 0;
312 blob.out = space;
313 code = pioctl(dir, VIOCGETAL((unsigned int) ((unsigned long) ((0x80000000) | (((sizeof(struct
ViceIoctl)) & ((1 << 13) - 1)) << 16) | ((('V'
)) << 8) | ((2)))))
, &blob, 1);
314 if (code) {
315 continue;
316 }
317 ta = ParseAcl(space);
318 if (ta->nplus <= 0)
319 continue;
320
321 for (te = ta->pluslist; te; te = te->next) {
322 if (((te->rights & PRSFS_INSERT4) && (te->rights & PRSFS_DELETE16))
323 || (te->rights & (PRSFS_WRITE2 | PRSFS_ADMINISTER64)))
324 if (strcmp(te->name, "system:administrators"))
325 return 0; /* somebody who we can't trust has got power */
326 }
327 }
328#endif /* INSECURE */
329
330 return 1;
331}
332
333/* Then, once we've found our own location, we look for a program named
334 * kpwvalid.
335 */
336
337/* look for a password-checking program named kpwvalid.
338 * It has to be in a secure place (same place as this executable)
339 */
340static int
341kpwvalid_is(char *dir)
342{
343 struct stat statbuff;
344 int len;
345
346 len = (int)strlen(dir);
347 strcpy(dir + len, "/kpwvalid");
348
349 if (stat(dir, &statbuff) < 0) {
350 /* if lstat fails, it's possible that it's transient, but
351 * unlikely. Let's hope it isn't, and continue... */
352 *(dir + len) = '\0';
353 return 0;
354 }
355
356 *(dir + len) = '\0';
357 return 1;
358}
359
360#ifdef AFS_NT40_ENV
361/* We don't allow the use of kpwvalid executable scripts to set policy
362 * for passwd changes.
363 */
364int
365init_child(char *myname)
366{
367
368 using_child = 0;
369 return using_child;
370
371}
372#else /* !NT40 */
373int
374init_child(char *myname)
375{
376 int pipe1[2], pipe2[2];
377 pid_t pid;
378 char dirpath[1024];
379 char *argv[2];
380
381 if (!(find_me(myname, dirpath) && is_secure(dirpath)
382 && kpwvalid_is(dirpath))) {
383 using_child = 0;
384 return 0;
385 }
386
387 /* make a couple of pipes, one for the child's stdin, and the other
388 * for the child's stdout. The parent writes to the former, and
389 * reads from the latter, the child reads from the former, and
390 * writes to the latter.
391 */
392 pipe(pipe1);
393 pipe(pipe2);
394
395 /* fork a child */
396 pid = fork();
397 if (pid == -1) {
398 using_child = 0;
399 perror("kpasswd: can't fork because ");
400 return (using_child);
401 }
402 if (pid == 0) { /* in child process */
403 /* tie stdin and stdout to these pipes */
404 /* if dup2 doesn't exist everywhere, close and then dup, but make */
405 /* sure that you really get stdin or stdout from the dup. */
406 if ((-1 == dup2(pipe1[0], 0)) || (-1 == dup2(pipe2[1], 1))) {
407 perror("kpasswd: can't exec kpwvalid because ");
408 exit(-1);
409 }
410
411 strcat(dirpath, "/kpwvalid");
412 argv[1] = NULL((void *)0);
413 argv[0] = dirpath;
414 execv(dirpath, argv);
415 return 0;
416 } else {
417 using_child = pid; /* save it for later */
418 childin = fdopen(pipe1[1], "w");
419 childout = fdopen(pipe2[0], "r");
420 return (using_child);
421 }
422}
423#endif /* not NT40 */
424
425int
426password_bad(char *pw)
427{
428 int rc;
429 rc = 0;
430
431 if (using_child) {
432 fprintf(childin, "%s\n", pw);
433 fflush(childin);
434 fscanf(childout, "%d", &rc);
435 }
436
437 return (rc);
438}
439
440/* this is originally only used to give the child the old password, so she
441 * can compare putative new passwords against it.
442 */
443int
444give_to_child(char *pw)
445{
446 int rc;
447 rc = 0;
448
449 if (using_child) {
450 fprintf(childin, "%s\n", pw);
451 fflush(childin);
452 }
453
454 return (rc);
455}
456
457/* quickly and painlessly
458 */
459int
460terminate_child(void)
461{
462 int rc;
463 rc = 0;
464
465#ifndef AFS_NT40_ENV
466 if (using_child) {
467 rc = kill(using_child, SIGKILL9);
468 }
469#endif
470 return (rc);
471}