Hi, > + op = SINGLEENTRY; > + arg = calloc(1, sizeof(char)*(7 + strlen(optarg))); > + arg = strcpy(arg, "shell:"); > + arg = strncat(arg, optarg, sizeof(arg) - 7); > + break; > > First, you could use asprintf(3) instead of the calloc/string dance. > > Second, unless mistaken, are you sure that your strncat() call is > correct? sizeof(arg) - 7 looks like a very nice overflow to me, at least > for anything that is 32 bits or lower. And for 64 bits, this would just > copy 1 byte. of course you're right. I know I had asprintf here first, and then an PATH_MAX array, but then changed it... Attached is a version with asprintf. Anyway, I just remembered this change is not possible anyway as users couldn't change their login shells anymore, which is the current behaviour. Regards, Julian
Index: chpass.c
===================================================================
RCS file: /cvsroot/src/usr.bin/chpass/chpass.c,v
retrieving revision 1.35
diff -u -r1.35 chpass.c
--- chpass.c 31 Aug 2011 16:24:57 -0000 1.35
+++ chpass.c 28 Nov 2011 21:31:38 -0000
@@ -80,13 +80,13 @@
int
main(int argc, char **argv)
{
- enum { NEWSH, LOADENTRY, EDITENTRY } op;
+ enum { LOADENTRY, EDITENTRY, SINGLEENTRY } op;
struct passwd *pw, lpw, old_pw;
- int ch, dfd, pfd, tfd;
+ int ch, dfd, pfd, tfd, i, ffound;
#ifdef YP
int yflag = 0;
#endif
- char *arg, *username = NULL;
+ char *arg, *opt, *username = NULL;
#ifdef __GNUC__
pw = NULL; /* XXX gcc -Wuninitialized */
@@ -97,14 +97,19 @@
#endif
op = EDITENTRY;
- while ((ch = getopt(argc, argv, "a:s:ly")) != -1)
+ while ((ch = getopt(argc, argv, "f:a:s:ly")) != -1)
switch (ch) {
case 'a':
op = LOADENTRY;
arg = optarg;
break;
case 's':
- op = NEWSH;
+ op = SINGLEENTRY;
+ if (asprintf(&arg, "shell:%s", optarg) <= 0)
+ errx(1, "asprintf");
+ break;
+ case 'f':
+ op = SINGLEENTRY;
arg = optarg;
break;
case 'l':
@@ -182,7 +187,7 @@
"\tUse the -l flag to load local.");
#endif
- if (op == EDITENTRY || op == NEWSH) {
+ if (op == EDITENTRY || op == SINGLEENTRY) {
if (username != NULL) {
pw = getpwnam(username);
if (pw == NULL)
@@ -204,12 +209,30 @@
}
}
- if (op == NEWSH) {
- /* protect p_shell -- it thinks NULL is /bin/sh */
- if (!arg[0])
+ if (op == SINGLEENTRY) {
+ /* Separate option and value. */
+ opt = strsep(&arg, ":");
+ if (opt == NULL || !strlen(opt) | !strlen(arg))
usage();
- if (p_shell(arg, pw, NULL))
- (*Pw_error)(NULL, 0, 1);
+ if (uid) // XXX: On the long run, let users change their own
entries.
+ baduser();
+
+ /* The option name has a space replaced by underscore. */
+ if (strchr(opt, '_'))
+ *(strchr(opt, '_')) = ' ';
+
+ /* Search for the right field. */
+ ffound = 0;
+ for (i = 0; list[i].prompt != NULL; i++)
+ if (!strcasecmp(opt, list[i].prompt)) {
+ if (list[i].func(arg, pw, &list[i]))
+ (*Pw_error)(NULL, 0, 1);
+ ffound = 1;
+ break;
+ }
+
+ if (!ffound)
+ errx(1, "invalid field specification: %s", opt);
}
if (op == LOADENTRY) {
@@ -303,7 +326,10 @@
(void)fprintf(stderr,
"usage: %s [-a list] [-s shell] [-l] [user]\n"
- " %s [-a list] [-s shell] [-y] [user]\n",
+ " %s [-a list] [-s shell] [-y] [user]\n"
+ " %s [-f option:value] [-y] [user]\n"
+ " %s [-f option:value] [-l] [user]\n",
+ getprogname(), getprogname(),
getprogname(), getprogname());
exit(1);
}
Attachment:
signature.asc
Description: PGP signature