View | Details | Raw Unified | Return to bug 1039361
Collapse All | Expand All

(-)a/src/ttyname.c (-81 / +60 lines)
Lines 1-5 Link Here
1
/*
1
/*
2
 * Copyright (c) 2012-2016 Todd C. Miller <Todd.Miller@courtesan.com>
2
 * Copyright (c) 2012-2017 Todd C. Miller <Todd.Miller@courtesan.com>
3
 *
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
5
 * purpose with or without fee is hereby granted, provided that the above
Lines 145-164 Link Here
145
}
145
}
146
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
146
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
147
/*
147
/*
148
 * Devices to search before doing a breadth-first scan.
148
 * Device nodes and directories to search before searching all of /dev
149
 */
149
 */
150
static char *search_devs[] = {
150
static char *search_devs[] = {
151
    "/dev/console",
151
    "/dev/console",
152
    "/dev/wscons",
152
    "/dev/pts/",	/* POSIX pty */
153
    "/dev/pts/",
153
    "/dev/vt/",		/* Solaris virtual console */
154
    "/dev/vt/",
154
    "/dev/term/",	/* Solaris serial ports */
155
    "/dev/term/",
155
    "/dev/zcons/",	/* Solaris zone console */
156
    "/dev/zcons/",
156
    "/dev/pty/",	/* HP-UX old-style pty */
157
    NULL
157
    NULL
158
};
158
};
159
159
160
/*
161
 * Device nodes to ignore when searching all of /dev
162
 */
160
static char *ignore_devs[] = {
163
static char *ignore_devs[] = {
161
    "/dev/fd/",
162
    "/dev/stdin",
164
    "/dev/stdin",
163
    "/dev/stdout",
165
    "/dev/stdout",
164
    "/dev/stderr",
166
    "/dev/stderr",
Lines 166-181 Link Here
166
};
168
};
167
169
168
/*
170
/*
169
 * Do a breadth-first scan of dir looking for the specified device.
171
 * Do a scan of a directory looking for the specified device.
172
 * Does not descend into subdirectories.
170
 * Returns name on success and NULL on failure, setting errno.
173
 * Returns name on success and NULL on failure, setting errno.
171
 */
174
 */
172
static char *
175
static char *
173
sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin, char *name, size_t namelen)
176
sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
174
{
177
{
175
    size_t sdlen, num_subdirs = 0, max_subdirs = 0;
178
    size_t sdlen;
176
    char pathbuf[PATH_MAX], **subdirs = NULL;
179
    char pathbuf[PATH_MAX];
177
    char *ret = NULL;
180
    char *ret = NULL;
178
    struct dirent *dp;
181
    struct dirent *dp;
182
    struct stat sb;
179
    unsigned int i;
183
    unsigned int i;
180
    DIR *d = NULL;
184
    DIR *d = NULL;
181
    debug_decl(sudo_ttyname_scan, SUDO_DEBUG_UTIL)
185
    debug_decl(sudo_ttyname_scan, SUDO_DEBUG_UTIL)
Lines 187-192 Link Here
187
    if ((d = opendir(dir)) == NULL)
191
    if ((d = opendir(dir)) == NULL)
188
	goto done;
192
	goto done;
189
193
194
    if (fstat(dirfd(d), &sb) == -1) {
195
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
196
	    "unable to fstat %s", dir);
197
	goto done;
198
    }
199
    if ((sb.st_mode & S_IWOTH) != 0) {
200
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
201
	    "ignoring world-writable directory %s", dir);
202
	errno = ENOENT;
203
	goto done;
204
    }
205
190
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
206
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
191
	"scanning for dev %u in %s", (unsigned int)rdev, dir);
207
	"scanning for dev %u in %s", (unsigned int)rdev, dir);
192
208
Lines 224-241 Link Here
224
	}
240
	}
225
	if (ignore_devs[i] != NULL)
241
	if (ignore_devs[i] != NULL)
226
	    continue;
242
	    continue;
227
	if (!builtin) {
228
	    /* Skip entries in search_devs; we already checked them. */
229
	    for (i = 0; search_devs[i] != NULL; i++) {
230
		len = strlen(search_devs[i]);
231
		if (search_devs[i][len - 1] == '/')
232
		    len--;
233
		if (d_len == len && strncmp(pathbuf, search_devs[i], len) == 0)
234
		    break;
235
	    }
236
	    if (search_devs[i] != NULL)
237
		continue;
238
	}
239
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF)
243
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF)
240
	/*
244
	/*
241
	 * Avoid excessive stat() calls by checking dp->d_type.
245
	 * Avoid excessive stat() calls by checking dp->d_type.
Lines 248-286 Link Here
248
		if (stat(pathbuf, &sb) == -1)
252
		if (stat(pathbuf, &sb) == -1)
249
		    continue;
253
		    continue;
250
		break;
254
		break;
251
	    case DT_DIR:
252
		/* Directory, no need to stat() it. */
253
		sb.st_mode = DTTOIF(dp->d_type);
254
		sb.st_rdev = 0;		/* quiet ccc-analyzer false positive */
255
		break;
256
	    default:
255
	    default:
257
		/* Not a character device, link or directory, skip it. */
256
		/* Not a character device or link, skip it. */
258
		continue;
257
		continue;
259
	}
258
	}
260
# else
259
# else
261
	if (stat(pathbuf, &sb) == -1)
260
	if (stat(pathbuf, &sb) == -1)
262
	    continue;
261
	    continue;
263
# endif
262
# endif
264
	if (S_ISDIR(sb.st_mode)) {
265
	    if (!builtin) {
266
		/* Add to list of subdirs to search. */
267
		if (num_subdirs + 1 > max_subdirs) {
268
		    char **new_subdirs;
269
270
		    new_subdirs = reallocarray(subdirs, max_subdirs + 64,
271
			sizeof(char *));
272
		    if (new_subdirs == NULL)
273
			goto done;
274
		    subdirs = new_subdirs;
275
		    max_subdirs += 64;
276
		}
277
		subdirs[num_subdirs] = strdup(pathbuf);
278
		if (subdirs[num_subdirs] == NULL)
279
		    goto done;
280
		num_subdirs++;
281
	    }
282
	    continue;
283
	}
284
	if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
263
	if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
285
	    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
264
	    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
286
		"resolved dev %u as %s", (unsigned int)rdev, pathbuf);
265
		"resolved dev %u as %s", (unsigned int)rdev, pathbuf);
Lines 296-311 Link Here
296
	}
275
	}
297
    }
276
    }
298
277
299
    /* Search subdirs if we didn't find it in the root level. */
300
    for (i = 0; ret == NULL && i < num_subdirs; i++)
301
	ret = sudo_ttyname_scan(subdirs[i], rdev, false, name, namelen);
302
303
done:
278
done:
304
    if (d != NULL)
279
    if (d != NULL)
305
	closedir(d);
280
	closedir(d);
306
    for (i = 0; i < num_subdirs; i++)
307
	free(subdirs[i]);
308
    free(subdirs);
309
    debug_return_str(ret);
281
    debug_return_str(ret);
310
}
282
}
311
283
Lines 324-330 Link Here
324
    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
296
    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
325
297
326
    /*
298
    /*
327
     * First check search_devs for common tty devices.
299
     * First check search_devs[] for common tty devices.
328
     */
300
     */
329
    for (sd = search_devs; (devname = *sd) != NULL; sd++) {
301
    for (sd = search_devs; (devname = *sd) != NULL; sd++) {
330
	len = strlen(devname);
302
	len = strlen(devname);
Lines 349-355 Link Here
349
		    "comparing dev %u to %s: no", (unsigned int)rdev, buf);
321
		    "comparing dev %u to %s: no", (unsigned int)rdev, buf);
350
	    } else {
322
	    } else {
351
		/* Traverse directory */
323
		/* Traverse directory */
352
		ret = sudo_ttyname_scan(devname, rdev, true, name, namelen);
324
		ret = sudo_ttyname_scan(devname, rdev, name, namelen);
353
		if (ret != NULL || errno == ENOMEM)
325
		if (ret != NULL || errno == ENOMEM)
354
		    goto done;
326
		    goto done;
355
	    }
327
	    }
Lines 367-375 Link Here
367
    }
339
    }
368
340
369
    /*
341
    /*
370
     * Not found?  Do a breadth-first traversal of /dev/.
342
     * Not found?  Check all device nodes in /dev.
371
     */
343
     */
372
    ret = sudo_ttyname_scan(_PATH_DEV, rdev, false, name, namelen);
344
    ret = sudo_ttyname_scan(_PATH_DEV, rdev, name, namelen);
373
345
374
done:
346
done:
375
    debug_return_str(ret);
347
    debug_return_str(ret);
Lines 493-520 Link Here
493
	len = getline(&line, &linesize, fp);
465
	len = getline(&line, &linesize, fp);
494
	fclose(fp);
466
	fclose(fp);
495
	if (len != -1) {
467
	if (len != -1) {
496
	    /* Field 7 is the tty dev (0 if no tty) */
468
	    /*
497
	    char *cp = line;
469
	     * Field 7 is the tty dev (0 if no tty).
498
	    char *ep = line;
470
	     * Since the process name at field 2 "(comm)" may include spaces,
499
	    const char *errstr;
471
	     * start at the last ')' found.
500
	    int field = 0;
472
	     */
501
	    while (*++ep != '\0') {
473
	    char *cp = strrchr(line, ')');
502
		if (*ep == ' ') {
474
	    if (cp != NULL) {
503
		    *ep = '\0';
475
		char *ep = cp;
504
		    if (++field == 7) {
476
		const char *errstr;
505
			dev_t tdev = strtonum(cp, INT_MIN, INT_MAX, &errstr);
477
		int field = 1;
506
			if (errstr) {
478
507
			    sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
479
		while (*++ep != '\0') {
508
				"%s: tty device %s: %s", path, cp, errstr);
480
		    if (*ep == ' ') {
481
			*ep = '\0';
482
			if (++field == 7) {
483
			    dev_t tdev = strtonum(cp, INT_MIN, INT_MAX, &errstr);
484
			    if (errstr) {
485
				sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
486
				    "%s: tty device %s: %s", path, cp, errstr);
487
			    }
488
			    if (tdev > 0) {
489
				errno = serrno;
490
				ret = sudo_ttyname_dev(tdev, name, namelen);
491
				goto done;
492
			    }
493
			    break;
509
			}
494
			}
510
			if (tdev > 0) {
495
			cp = ep + 1;
511
			    errno = serrno;
512
			    ret = sudo_ttyname_dev(tdev, name, namelen);
513
			    goto done;
514
			}
515
			break;
516
		    }
496
		    }
517
		    cp = ep + 1;
518
		}
497
		}
519
	    }
498
	    }
520
	}
499
	}

Return to bug 1039361