Print this page
2989 Eliminate use of LOGNAME_MAX in ON
1166 useradd have warning with name more 8 chars
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/newtask/newtask.c
+++ new/usr/src/cmd/newtask/newtask.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 + * Copyright (c) 2013 Gary Mills
24 + *
23 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 26 * Use is subject to license terms.
25 27 */
26 28
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 29 #include <sys/types.h>
30 30 #include <sys/task.h>
31 31
32 32 #include <alloca.h>
33 33 #include <libproc.h>
34 34 #include <libintl.h>
35 35 #include <libgen.h>
36 36 #include <limits.h>
37 37 #include <project.h>
38 38 #include <pwd.h>
39 39 #include <secdb.h>
40 40 #include <stdio.h>
41 41 #include <stdlib.h>
42 42 #include <string.h>
43 43 #include <sys/varargs.h>
44 44 #include <unistd.h>
45 45 #include <errno.h>
46 46 #include <signal.h>
47 47 #include <priv_utils.h>
48 48
49 +#ifdef LOGNAME_MAX_ILLUMOS
50 +#define _LOGNAME_MAX LOGNAME_MAX_ILLUMOS
51 +#else /* LOGNAME_MAX_ILLUMOS */
52 +#define _LOGNAME_MAX LOGNAME_MAX
53 +#endif /* LOGNAME_MAX_ILLUMOS */
54 +
49 55 #include "utils.h"
50 56
51 57 #define OPTIONS_STRING "Fc:lp:v"
52 58 #define NENV 8
53 59 #define ENVSIZE 255
54 60 #define PATH "PATH=/usr/bin"
55 61 #define SUPATH "PATH=/usr/sbin:/usr/bin"
56 62 #define SHELL "/usr/bin/sh"
57 63 #define SHELL2 "/sbin/sh"
58 64 #define TIMEZONEFILE "/etc/default/init"
59 65 #define LOGINFILE "/etc/default/login"
60 66 #define GLOBAL_ERR_SZ 1024
61 67 #define GRAB_RETRY_MAX 100
62 68
63 69 static const char *pname;
64 70 extern char **environ;
65 71 static char *supath = SUPATH;
66 72 static char *path = PATH;
67 73 static char global_error[GLOBAL_ERR_SZ];
68 74 static int verbose = 0;
69 75
70 76 static priv_set_t *nset;
71 77
72 78 /* Private definitions for libproject */
73 79 extern projid_t setproject_proc(const char *, const char *, int, pid_t,
74 80 struct ps_prochandle *, struct project *);
75 81 extern priv_set_t *setproject_initpriv(void);
76 82
77 83 static void usage(void);
78 84
79 85 static void preserve_error(const char *format, ...);
80 86
81 87 static int update_running_proc(int, char *, char *);
82 88 static int set_ids(struct ps_prochandle *, struct project *,
83 89 struct passwd *);
84 90 static struct passwd *match_user(uid_t, char *, int);
85 91 static void setproject_err(char *, char *, int, struct project *);
86 92
87 93 static void
88 94 usage(void)
89 95 {
90 96 (void) fprintf(stderr, gettext("usage: \n\t%s [-v] [-p project] "
91 97 "[-c pid | [-Fl] [command [args ...]]]\n"), pname);
92 98 exit(2);
93 99 }
94 100
95 101 int
96 102 main(int argc, char *argv[])
97 103 {
98 104 int c;
99 105 struct passwd *pw;
100 106 char *projname = NULL;
101 107 uid_t uid;
102 108 int login_flag = 0;
103 109 int finalize_flag = TASK_NORMAL;
104 110 int newproj_flag = 0;
105 111 taskid_t taskid;
106 112 char *shell;
107 113 char *env[NENV];
108 114 char **targs;
109 115 char *filename, *procname = NULL;
110 116 int error;
111 117
112 118 nset = setproject_initpriv();
113 119 if (nset == NULL)
114 120 die(gettext("privilege initialization failed\n"));
115 121
116 122 pname = getpname(argv[0]);
117 123
118 124 while ((c = getopt(argc, argv, OPTIONS_STRING)) != EOF) {
119 125 switch (c) {
120 126 case 'v':
121 127 verbose = 1;
122 128 break;
123 129 case 'p':
124 130 newproj_flag = 1;
125 131 projname = optarg;
126 132 break;
127 133 case 'F':
128 134 finalize_flag = TASK_FINAL;
129 135 break;
130 136 case 'l':
131 137 login_flag++;
132 138 break;
133 139 case 'c':
134 140 procname = optarg;
135 141 break;
136 142 case '?':
137 143 default:
138 144 usage();
139 145 /*NOTREACHED*/
140 146 }
141 147 }
142 148
143 149 /* -c option is invalid with -F, -l, or a specified command */
144 150 if ((procname != NULL) &&
145 151 (finalize_flag == TASK_FINAL || login_flag || optind < argc))
146 152 usage();
147 153
148 154 if (procname != NULL) {
149 155 /* Change project/task of an existing process */
150 156 return (update_running_proc(newproj_flag, procname, projname));
151 157 }
152 158
153 159 /*
154 160 * Get user data, so that we can confirm project membership as
155 161 * well as construct an appropriate login environment.
156 162 */
157 163 uid = getuid();
158 164 if ((pw = match_user(uid, projname, 1)) == NULL) {
159 165 die("%s\n", global_error);
160 166 }
161 167
162 168 /*
163 169 * If no projname was specified, we're just creating a new task
164 170 * under the current project, so we can just set the new taskid.
165 171 * If our project is changing, we need to update any attendant
166 172 * pool/rctl bindings, so let setproject() do the dirty work.
167 173 */
168 174 (void) __priv_bracket(PRIV_ON);
169 175 if (projname == NULL) {
170 176 if (settaskid(getprojid(), finalize_flag) == -1)
171 177 if (errno == EAGAIN)
172 178 die(gettext("resource control limit has been "
173 179 "reached"));
174 180 else
175 181 die(gettext("settaskid failed"));
176 182 } else {
177 183 if ((error = setproject(projname,
178 184 pw->pw_name, finalize_flag)) != 0) {
179 185 setproject_err(pw->pw_name, projname, error, NULL);
180 186 if (error < 0)
181 187 die("%s\n", global_error);
182 188 else
183 189 warn("%s\n", global_error);
184 190 }
185 191 }
186 192 __priv_relinquish();
187 193
188 194 taskid = gettaskid();
189 195
190 196 if (verbose)
191 197 (void) fprintf(stderr, "%d\n", (int)taskid);
192 198
193 199 /*
194 200 * Validate user's shell from passwd database.
195 201 */
196 202 if (strcmp(pw->pw_shell, "") == 0) {
197 203 if (access(SHELL, X_OK) == 0)
198 204 pw->pw_shell = SHELL;
199 205 else
200 206 pw->pw_shell = SHELL2;
201 207 }
202 208
203 209 if (login_flag) {
204 210 /*
205 211 * Since we've been invoked as a "simulated login", set up the
206 212 * environment.
207 213 */
208 214 char *cur_tz = getenv("TZ");
209 215 char *cur_term = getenv("TERM");
210 216
211 217 char **envnext;
212 218
213 219 size_t len_home = strlen(pw->pw_dir) + strlen("HOME=") + 1;
214 220 size_t len_logname = strlen(pw->pw_name) + strlen("LOGNAME=") +
215 221 1;
216 222 size_t len_shell = strlen(pw->pw_shell) + strlen("SHELL=") + 1;
217 223 size_t len_mail = strlen(pw->pw_name) +
218 224 strlen("MAIL=/var/mail/") + 1;
219 225 size_t len_tz;
220 226 size_t len_term;
221 227
222 228 char *env_home = safe_malloc(len_home);
223 229 char *env_logname = safe_malloc(len_logname);
224 230 char *env_shell = safe_malloc(len_shell);
225 231 char *env_mail = safe_malloc(len_mail);
226 232 char *env_tz;
227 233 char *env_term;
228 234
229 235 (void) snprintf(env_home, len_home, "HOME=%s", pw->pw_dir);
230 236 (void) snprintf(env_logname, len_logname, "LOGNAME=%s",
231 237 pw->pw_name);
232 238 (void) snprintf(env_shell, len_shell, "SHELL=%s", pw->pw_shell);
233 239 (void) snprintf(env_mail, len_mail, "MAIL=/var/mail/%s",
234 240 pw->pw_name);
235 241
236 242 env[0] = env_home;
237 243 env[1] = env_logname;
238 244 env[2] = (pw->pw_uid == 0 ? supath : path);
239 245 env[3] = env_shell;
240 246 env[4] = env_mail;
241 247 env[5] = NULL;
242 248 env[6] = NULL;
243 249 env[7] = NULL;
244 250
245 251 envnext = (char **)&env[5];
246 252
247 253 /*
248 254 * It's possible that TERM wasn't defined in the outer
249 255 * environment.
250 256 */
251 257 if (cur_term != NULL) {
252 258 len_term = strlen(cur_term) + strlen("TERM=") + 1;
253 259 env_term = safe_malloc(len_term);
254 260
255 261 (void) snprintf(env_term, len_term, "TERM=%s",
256 262 cur_term);
257 263 *envnext = env_term;
258 264 envnext++;
259 265 }
260 266
261 267 /*
262 268 * It is also possible that TZ wasn't defined in the outer
263 269 * environment. In that case, we must attempt to open the file
264 270 * defining the default timezone and select the appropriate
265 271 * entry. If there is no default timezone there, try
266 272 * TIMEZONE in /etc/default/login, duplicating the algorithm
267 273 * that login uses.
268 274 */
269 275 if (cur_tz != NULL) {
270 276 len_tz = strlen(cur_tz) + strlen("TZ=") + 1;
271 277 env_tz = safe_malloc(len_tz);
272 278
273 279 (void) snprintf(env_tz, len_tz, "TZ=%s", cur_tz);
274 280 *envnext = env_tz;
275 281 } else {
276 282 if ((env_tz = getdefault(TIMEZONEFILE, "TZ=",
277 283 "TZ=")) != NULL)
278 284 *envnext = env_tz;
279 285 else {
280 286 env_tz = getdefault(LOGINFILE, "TIMEZONE=",
281 287 "TZ=");
282 288 *envnext = env_tz;
283 289 }
284 290 }
285 291
286 292 environ = (char **)&env[0];
287 293
288 294 /*
289 295 * Prefix the shell string with a hyphen, indicating a login
290 296 * shell.
291 297 */
292 298 shell = safe_malloc(PATH_MAX);
293 299 (void) snprintf(shell, PATH_MAX, "-%s", basename(pw->pw_shell));
294 300 } else {
295 301 shell = basename(pw->pw_shell);
296 302 }
297 303
298 304 /*
299 305 * If there are no arguments, we launch the user's shell; otherwise, the
300 306 * remaining commands are assumed to form a valid command invocation
301 307 * that we can exec.
302 308 */
303 309 if (optind >= argc) {
304 310 targs = alloca(2 * sizeof (char *));
305 311 filename = pw->pw_shell;
306 312 targs[0] = shell;
307 313 targs[1] = NULL;
308 314 } else {
309 315 targs = &argv[optind];
310 316 filename = targs[0];
311 317 }
312 318
313 319 if (execvp(filename, targs) == -1)
314 320 die(gettext("exec of %s failed"), targs[0]);
315 321
316 322 /*
317 323 * We should never get here.
318 324 */
319 325 return (1);
320 326 }
321 327
322 328 static int
323 329 update_running_proc(int newproj_flag, char *procname, char *projname)
324 330 {
325 331 struct ps_prochandle *p;
326 332 prcred_t original_prcred, current_prcred;
327 333 projid_t prprojid;
328 334 taskid_t taskid;
329 335 int error = 0, gret;
330 336 struct project project;
331 337 char prbuf[PROJECT_BUFSZ];
332 338 struct passwd *passwd_entry;
333 339 int grab_retry_count = 0;
334 340
335 341 /*
336 342 * Catch signals from terminal. There isn't much sense in
337 343 * doing anything but ignoring them since we don't do anything
338 344 * after the point we'd be capable of handling them again.
339 345 */
340 346 (void) sigignore(SIGHUP);
341 347 (void) sigignore(SIGINT);
342 348 (void) sigignore(SIGQUIT);
343 349 (void) sigignore(SIGTERM);
344 350
345 351 /* flush stdout before grabbing the proc to avoid deadlock */
346 352 (void) fflush(stdout);
347 353
348 354 /*
349 355 * We need to grab the process, which will force it to stop execution
350 356 * until the grab is released, in order to aquire some information about
351 357 * it, such as its current project (which is achieved via an injected
352 358 * system call and therefore needs an agent) and its credentials. We
353 359 * will then need to release it again because it may be a process that
354 360 * we rely on for later calls, for example nscd.
355 361 */
356 362 if ((p = proc_arg_grab(procname, PR_ARG_PIDS, 0, &gret)) == NULL) {
357 363 warn(gettext("failed to grab for process %s: %s\n"),
358 364 procname, Pgrab_error(gret));
359 365 return (1);
360 366 }
361 367 if (Pcreate_agent(p) != 0) {
362 368 Prelease(p, 0);
363 369 warn(gettext("cannot control process %s\n"), procname);
364 370 return (1);
365 371 }
366 372
367 373 /*
368 374 * The victim process is now held. Do not call any functions
369 375 * which generate stdout/stderr until the process has been
370 376 * released.
371 377 */
372 378
373 379 /*
374 380 * The target process will soon be restarted (in case it is in newtask's
375 381 * execution path) and then stopped again. We need to ensure that our cached
376 382 * data doesn't change while the process runs so return here if the target
377 383 * process changes its user id in between our stop operations, so that we can
378 384 * try again.
379 385 */
380 386 pgrab_retry:
381 387
382 388 /* Cache required information about the process. */
383 389 if (Pcred(p, &original_prcred, 0) != 0) {
384 390 preserve_error(gettext("cannot get process credentials %s\n"),
385 391 procname);
386 392 error = 1;
387 393 }
388 394 if ((prprojid = pr_getprojid(p)) == -1) {
389 395 preserve_error(gettext("cannot get process project id %s\n"),
390 396 procname);
391 397 error = 1;
392 398 }
393 399
394 400 /*
395 401 * We now have all the required information, so release the target
396 402 * process and perform our sanity checks. The process needs to be
397 403 * running at this point because it may be in the execution path of the
398 404 * calls made below.
399 405 */
400 406 Pdestroy_agent(p);
401 407 Prelease(p, 0);
402 408
403 409 /* if our data acquisition failed, then we can't continue. */
404 410 if (error) {
405 411 warn("%s\n", global_error);
406 412 return (1);
407 413 }
408 414
409 415 if (newproj_flag == 0) {
410 416 /*
411 417 * Just changing the task, so set projname to the current
412 418 * project of the running process.
413 419 */
414 420 if (getprojbyid(prprojid, &project, &prbuf,
415 421 PROJECT_BUFSZ) == NULL) {
416 422 warn(gettext("unable to get project name "
417 423 "for projid %d"), prprojid);
418 424 return (1);
419 425 }
420 426 projname = project.pj_name;
421 427 } else {
422 428 /*
423 429 * cache info for the project which user passed in via the
424 430 * command line
425 431 */
426 432 if (getprojbyname(projname, &project, &prbuf,
427 433 PROJECT_BUFSZ) == NULL) {
428 434 warn(gettext("unknown project \"%s\"\n"), projname);
429 435 return (1);
430 436 }
431 437 }
432 438
433 439 /*
434 440 * Use our cached information to verify that the owner of the running
435 441 * process is a member of proj
436 442 */
437 443 if ((passwd_entry = match_user(original_prcred.pr_ruid,
438 444 projname, 0)) == NULL) {
439 445 warn("%s\n", global_error);
440 446 return (1);
441 447 }
442 448
443 449 /*
444 450 * We can now safely stop the process again in order to change the
445 451 * project and taskid as required.
446 452 */
447 453 if ((p = proc_arg_grab(procname, PR_ARG_PIDS, 0, &gret)) == NULL) {
448 454 warn(gettext("failed to grab for process %s: %s\n"),
449 455 procname, Pgrab_error(gret));
450 456 return (1);
451 457 }
452 458 if (Pcreate_agent(p) != 0) {
453 459 Prelease(p, 0);
454 460 warn(gettext("cannot control process %s\n"), procname);
455 461 return (1);
456 462 }
457 463
458 464 /*
459 465 * Now that the target process is stopped, check the validity of our
460 466 * cached info. If we aren't superuser then match_user() will have
461 467 * checked to make sure that the owner of the process is in the relevant
462 468 * project. If our ruid has changed, then match_user()'s conclusion may
463 469 * be invalid.
464 470 */
465 471 if (getuid() != 0) {
466 472 if (Pcred(p, ¤t_prcred, 0) != 0) {
467 473 Pdestroy_agent(p);
468 474 Prelease(p, 0);
469 475 warn(gettext("can't get process credentials %s\n"),
470 476 procname);
471 477 return (1);
472 478 }
473 479
474 480 if (original_prcred.pr_ruid != current_prcred.pr_ruid) {
475 481 if (grab_retry_count++ < GRAB_RETRY_MAX)
476 482 goto pgrab_retry;
477 483
478 484 warn(gettext("process consistently changed its "
479 485 "user id %s\n"), procname);
480 486 return (1);
481 487 }
482 488 }
483 489
484 490 error = set_ids(p, &project, passwd_entry);
485 491
486 492 if (verbose)
487 493 taskid = pr_gettaskid(p);
488 494
489 495 Pdestroy_agent(p);
490 496 Prelease(p, 0);
491 497
492 498 if (error) {
493 499 /*
494 500 * error is serious enough to stop, only if negative.
495 501 * Otherwise, it simply indicates one of the resource
496 502 * control assignments failed, which is worth warning
497 503 * about.
498 504 */
499 505 warn("%s\n", global_error);
500 506 if (error < 0)
501 507 return (1);
502 508 }
503 509
504 510 if (verbose)
505 511 (void) fprintf(stderr, "%d\n", (int)taskid);
506 512
507 513 return (0);
508 514 }
509 515
510 516 static int
511 517 set_ids(struct ps_prochandle *p, struct project *project,
512 518 struct passwd *passwd_entry)
513 519 {
514 520 int be_su = 0;
515 521 prcred_t old_prcred;
516 522 int error;
517 523 prpriv_t *old_prpriv, *new_prpriv;
518 524 size_t prsz = sizeof (prpriv_t);
519 525 priv_set_t *eset, *pset;
520 526 int ind;
521 527
522 528 if (Pcred(p, &old_prcred, 0) != 0) {
523 529 preserve_error(gettext("can't get process credentials"));
524 530 return (1);
525 531 }
526 532
527 533 old_prpriv = proc_get_priv(Pstatus(p)->pr_pid);
528 534 if (old_prpriv == NULL) {
529 535 preserve_error(gettext("can't get process privileges"));
530 536 return (1);
531 537 }
532 538
533 539 prsz = PRIV_PRPRIV_SIZE(old_prpriv);
534 540
535 541 new_prpriv = malloc(prsz);
536 542 if (new_prpriv == NULL) {
537 543 preserve_error(gettext("can't allocate memory"));
538 544 free(old_prpriv);
539 545 return (1);
540 546 }
541 547
542 548 (void) memcpy(new_prpriv, old_prpriv, prsz);
543 549
544 550 /*
545 551 * If the process already has the proc_taskid privilege,
546 552 * we don't need to elevate its privileges; if it doesn't,
547 553 * we try to do it here.
548 554 * As we do not wish to leave a window in which the process runs
549 555 * with elevated privileges, we make sure that the process dies
550 556 * when we go away unexpectedly.
551 557 */
552 558
553 559 ind = priv_getsetbyname(PRIV_EFFECTIVE);
554 560 eset = (priv_set_t *)&new_prpriv->pr_sets[new_prpriv->pr_setsize * ind];
555 561 ind = priv_getsetbyname(PRIV_PERMITTED);
556 562 pset = (priv_set_t *)&new_prpriv->pr_sets[new_prpriv->pr_setsize * ind];
557 563
558 564 if (!priv_issubset(nset, eset)) {
559 565 be_su = 1;
560 566 priv_union(nset, eset);
561 567 priv_union(nset, pset);
562 568 if (Psetflags(p, PR_KLC) != 0) {
563 569 preserve_error(gettext("cannot set process "
564 570 "privileges"));
565 571 (void) Punsetflags(p, PR_KLC);
566 572 free(new_prpriv);
567 573 free(old_prpriv);
568 574 return (1);
569 575 }
570 576 (void) __priv_bracket(PRIV_ON);
571 577 if (Psetpriv(p, new_prpriv) != 0) {
572 578 (void) __priv_bracket(PRIV_OFF);
573 579 preserve_error(gettext("cannot set process "
574 580 "privileges"));
575 581 (void) Punsetflags(p, PR_KLC);
576 582 free(new_prpriv);
577 583 free(old_prpriv);
578 584 return (1);
579 585 }
580 586 (void) __priv_bracket(PRIV_OFF);
581 587 }
582 588
583 589 (void) __priv_bracket(PRIV_ON);
584 590 if ((error = setproject_proc(project->pj_name,
585 591 passwd_entry->pw_name, 0, Pstatus(p)->pr_pid, p, project)) != 0) {
586 592 /* global_error is set by setproject_err */
587 593 setproject_err(passwd_entry->pw_name, project->pj_name,
588 594 error, project);
589 595 }
590 596 (void) __priv_bracket(PRIV_OFF);
591 597
592 598 /* relinquish added privileges */
593 599 if (be_su) {
594 600 (void) __priv_bracket(PRIV_ON);
595 601 if (Psetpriv(p, old_prpriv) != 0) {
596 602 /*
597 603 * We shouldn't ever be in a state where we can't
598 604 * set the process back to its old creds, but we
599 605 * don't want to take the chance of leaving a
600 606 * non-privileged process with enhanced creds. So,
601 607 * release the process from libproc control, knowing
602 608 * that it will be killed.
603 609 */
604 610 (void) __priv_bracket(PRIV_OFF);
605 611 Pdestroy_agent(p);
606 612 die(gettext("cannot relinquish superuser credentials "
607 613 "for pid %d. The process was killed."),
608 614 Pstatus(p)->pr_pid);
609 615 }
610 616 (void) __priv_bracket(PRIV_OFF);
611 617 if (Punsetflags(p, PR_KLC) != 0)
612 618 preserve_error(gettext("error relinquishing "
613 619 "credentials. Process %d will be killed."),
614 620 Pstatus(p)->pr_pid);
615 621 }
616 622 free(new_prpriv);
617 623 free(old_prpriv);
618 624
619 625 return (error);
620 626 }
621 627
622 628 /*
623 629 * preserve_error() should be called rather than warn() by any
624 630 * function that is called while the victim process is being
625 631 * held by Pgrab.
626 632 *
627 633 * It saves a single error message to be printed until after
628 634 * the process has been released. Since multiple errors are not
629 635 * stored, any error should be considered critical.
630 636 */
631 637 void
632 638 preserve_error(const char *format, ...)
633 639 {
634 640 va_list alist;
635 641
636 642 va_start(alist, format);
637 643
638 644 /*
639 645 * GLOBAL_ERR_SZ is pretty big. If the error is longer
640 646 * than that, just truncate it, rather than chance missing
641 647 * the error altogether.
642 648 */
643 649 (void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist);
644 650
645 651 va_end(alist);
646 652
↓ open down ↓ |
588 lines elided |
↑ open up ↑ |
647 653 }
648 654
649 655 /*
650 656 * Given the input arguments, return the passwd structure that matches best.
651 657 * Also, since we use getpwnam() and friends, subsequent calls to this
652 658 * function will re-use the memory previously returned.
653 659 */
654 660 static struct passwd *
655 661 match_user(uid_t uid, char *projname, int is_my_uid)
656 662 {
657 - char prbuf[PROJECT_BUFSZ], username[LOGNAME_MAX+1];
663 + char prbuf[PROJECT_BUFSZ], username[_LOGNAME_MAX+1];
658 664 struct project prj;
659 665 char *tmp_name;
660 666 struct passwd *pw = NULL;
661 667
662 668 /*
663 669 * In order to allow users with the same UID but distinguishable
664 670 * user names to be in different projects we play a guessing
665 671 * game of which username is most appropriate. If we're checking
666 672 * for the uid of the calling process, the login name is a
667 673 * good starting point.
668 674 */
669 675 if (is_my_uid) {
670 676 if ((tmp_name = getlogin()) == NULL ||
671 677 (pw = getpwnam(tmp_name)) == NULL || (pw->pw_uid != uid) ||
672 678 (pw->pw_name == NULL))
673 679 pw = NULL;
674 680 }
675 681
676 682 /*
677 683 * If the login name doesn't work, we try the first match for
678 684 * the current uid in the password file.
679 685 */
680 686 if (pw == NULL) {
681 687 if (((pw = getpwuid(uid)) == NULL) || pw->pw_name == NULL) {
682 688 preserve_error(gettext("cannot find username "
683 689 "for uid %d"), uid);
684 690 return (NULL);
685 691 }
686 692 }
687 693
688 694 /*
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
689 695 * If projname wasn't supplied, we've done our best, so just return
690 696 * what we've got now. Alternatively, if newtask's invoker has
691 697 * superuser privileges, return the pw structure we've got now, with
692 698 * no further checking from inproj(). Superuser should be able to
693 699 * join any project, and the subsequent call to setproject() will
694 700 * allow this.
695 701 */
696 702 if (projname == NULL || getuid() == (uid_t)0)
697 703 return (pw);
698 704
699 - (void) strcpy(username, pw->pw_name);
705 + (void) strncpy(username, pw->pw_name, sizeof (username) - 1);
706 + username[sizeof (username) - 1] = '\0';
700 707
701 708 if (inproj(username, projname, prbuf, PROJECT_BUFSZ) == 0) {
702 709 char **u;
703 710 tmp_name = NULL;
704 711
705 712 /*
706 713 * If the previous guesses didn't work, walk through all
707 714 * project members and test for UID-equivalence.
708 715 */
709 716
710 717 if (getprojbyname(projname, &prj, prbuf,
711 718 PROJECT_BUFSZ) == NULL) {
712 719 preserve_error(gettext("unknown project \"%s\""),
713 720 projname);
714 721 return (NULL);
715 722 }
716 723
717 724 for (u = prj.pj_users; *u; u++) {
718 725 if ((pw = getpwnam(*u)) == NULL)
719 726 continue;
720 727
721 728 if (pw->pw_uid == uid) {
722 729 tmp_name = pw->pw_name;
723 730 break;
724 731 }
725 732 }
726 733
727 734 if (tmp_name == NULL) {
728 735 preserve_error(gettext("user \"%s\" is not a member of "
729 736 "project \"%s\""), username, projname);
730 737 return (NULL);
731 738 }
732 739 }
733 740
734 741 return (pw);
735 742 }
736 743
737 744 void
738 745 setproject_err(char *username, char *projname, int error, struct project *proj)
739 746 {
740 747 kva_t *kv_array = NULL;
741 748 char prbuf[PROJECT_BUFSZ];
742 749 struct project local_proj;
743 750
744 751 switch (error) {
745 752 case SETPROJ_ERR_TASK:
746 753 if (errno == EAGAIN)
747 754 preserve_error(gettext("resource control limit has "
748 755 "been reached"));
749 756 else if (errno == ESRCH)
750 757 preserve_error(gettext("user \"%s\" is not a member of "
751 758 "project \"%s\""), username, projname);
752 759 else if (errno == EACCES)
753 760 preserve_error(gettext("the invoking task is final"));
754 761 else
755 762 preserve_error(
756 763 gettext("could not join project \"%s\""),
757 764 projname);
758 765 break;
759 766 case SETPROJ_ERR_POOL:
760 767 if (errno == EACCES)
761 768 preserve_error(gettext("no resource pool accepting "
762 769 "default bindings exists for project \"%s\""),
763 770 projname);
764 771 else if (errno == ESRCH)
765 772 preserve_error(gettext("specified resource pool does "
766 773 "not exist for project \"%s\""), projname);
767 774 else
768 775 preserve_error(gettext("could not bind to default "
769 776 "resource pool for project \"%s\""), projname);
770 777 break;
771 778 default:
772 779 if (error <= 0) {
773 780 preserve_error(gettext("setproject failed for "
774 781 "project \"%s\""), projname);
775 782 return;
776 783 }
777 784 /*
778 785 * If we have a stopped target process it may be in
779 786 * getprojbyname()'s execution path which would make it unsafe
780 787 * to access the project table, so only do that if the caller
781 788 * hasn't provided a cached version of the project structure.
782 789 */
783 790 if (proj == NULL)
784 791 proj = getprojbyname(projname, &local_proj, prbuf,
785 792 PROJECT_BUFSZ);
786 793
787 794 if (proj == NULL || (kv_array = _str2kva(proj->pj_attr,
788 795 KV_ASSIGN, KV_DELIMITER)) == NULL ||
789 796 kv_array->length < error) {
790 797 preserve_error(gettext("warning, resource control "
791 798 "assignment failed for project \"%s\" "
792 799 "attribute %d"),
793 800 projname, error);
794 801 if (kv_array)
795 802 _kva_free(kv_array);
796 803 return;
797 804 }
798 805 preserve_error(gettext("warning, %s resource control "
799 806 "assignment failed for project \"%s\""),
800 807 kv_array->data[error - 1].key, projname);
801 808 _kva_free(kv_array);
802 809 }
803 810 }
↓ open down ↓ |
94 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX