|
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 |
} |