summaryrefslogtreecommitdiff
path: root/source3/utils/smbpasswd.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/utils/smbpasswd.c')
-rw-r--r--source3/utils/smbpasswd.c279
1 files changed, 229 insertions, 50 deletions
diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c
index 9a244a28b5..e3237a0b3c 100644
--- a/source3/utils/smbpasswd.c
+++ b/source3/utils/smbpasswd.c
@@ -37,6 +37,10 @@ struct
{0, NULL}
};
+/******************************************************
+ Convert a hex password.
+*******************************************************/
+
static int gethexpwd(char *p, char *pwd)
{
int i;
@@ -60,6 +64,10 @@ static int gethexpwd(char *p, char *pwd)
return (True);
}
+/******************************************************
+ Find a password entry by name.
+*******************************************************/
+
static struct smb_passwd *
_my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
BOOL *got_valid_nt_entry, long *pwd_seekpos)
@@ -76,6 +84,8 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
long uidval;
long linebuf_len;
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
/*
* Scan the file, a line at a time and check if the name matches.
*/
@@ -159,6 +169,8 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
*got_valid_nt_entry = False;
pw_buf.smb_nt_passwd = NULL; /* No NT password (yet)*/
+ pw_buf.acct_ctrl |= ACB_DISABLED;
+
/* Now check if the NT compatible password is
available. */
p += 33; /* Move to the first character of the line after
@@ -184,6 +196,7 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
if (!strncasecmp((char *)p, "NO PASSWORD", 11)) {
pw_buf.smb_passwd = NULL; /* No password */
+ pw_buf.acct_ctrl |= ACB_PWNOTREQ;
} else {
if(!gethexpwd((char *)p,(char *)smbpwd))
return False;
@@ -207,25 +220,126 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
if (gethexpwd((char *)p,(char *)smbntpwd))
pw_buf.smb_nt_passwd = smbntpwd;
}
+
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
}
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p == '[') {
+ BOOL finished = False;
+
+ pw_buf.acct_ctrl = 0;
+
+ for(p++;*p && !finished; p++) {
+ switch (*p) {
+ case 'N':
+ /* 'N'o password. */
+ pw_buf.acct_ctrl |= ACB_PWNOTREQ;
+ break;
+ case 'D':
+ /* 'D'isabled. */
+ pw_buf.acct_ctrl |= ACB_DISABLED;
+ break;
+ case 'H':
+ /* 'H'omedir required. */
+ pw_buf.acct_ctrl |= ACB_HOMDIRREQ;
+ break;
+ case 'T':
+ /* 'T'emp account. */
+ pw_buf.acct_ctrl |= ACB_TEMPDUP;
+ break;
+ case 'U':
+ /* 'U'ser account (normal). */
+ pw_buf.acct_ctrl |= ACB_NORMAL;
+ break;
+ case 'M':
+ /* 'M'NS logon user account. What is this ? */
+ pw_buf.acct_ctrl |= ACB_MNS;
+ break;
+ case 'W':
+ /* 'W'orkstation account. */
+ pw_buf.acct_ctrl |= ACB_WSTRUST;
+ break;
+ case 'S':
+ /* 'S'erver account. */
+ pw_buf.acct_ctrl |= ACB_SVRTRUST;
+ break;
+ case 'L':
+ /* 'L'ocked account. */
+ pw_buf.acct_ctrl |= ACB_AUTOLOCK;
+ break;
+ case 'X':
+ /* No 'X'piry. */
+ pw_buf.acct_ctrl |= ACB_PWNOEXP;
+ break;
+ case 'I':
+ /* 'I'nterdomain trust account. */
+ pw_buf.acct_ctrl |= ACB_DOMTRUST;
+ break;
+
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default:
+ finished = True;
+ }
+ }
+
+ /* Must have some account type set. */
+ if(pw_buf.acct_ctrl == 0)
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently machine accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
+ pw_buf.acct_ctrl &= ~ACB_NORMAL;
+ pw_buf.acct_ctrl |= ACB_WSTRUST;
+ }
+ }
return &pw_buf;
}
return NULL;
}
-/*
- * Print command usage on stderr and die.
- */
+/**********************************************************
+ Allocate an unused uid in the smbpasswd file to a new
+ machine account.
+***********************************************************/
+
+int get_machine_uid(void)
+{
+ return 65534;
+}
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+
static void usage(char *name, BOOL is_root)
{
if(is_root)
- fprintf(stderr, "Usage is : %s [-a] [username] [password]\n\
-%s: [-r machine] [username] [password]\n%s: [-h]", name, name, name);
+ fprintf(stderr, "Usage is : %s [-a] [-d] [-m] [-n] [username] [password]\n\
+%s: [-r machine] [username] [password]\n%s: [-h]\n", name, name, name);
else
fprintf(stderr, "Usage is : %s [-h] [-r machine] [password]\n", name);
exit(1);
}
+/*********************************************************
+ Start here.
+**********************************************************/
+
int main(int argc, char **argv)
{
extern char *optarg;
@@ -233,9 +347,8 @@ int main(int argc, char **argv)
char *prog_name;
int real_uid;
struct passwd *pwd;
+ struct passwd machine_account_pwd;
fstring old_passwd;
- uchar old_p16[16];
- uchar old_nt_p16[16];
fstring new_passwd;
uchar new_p16[16];
uchar new_nt_p16[16];
@@ -255,17 +368,20 @@ int main(int argc, char **argv)
char readbuf[16 * 1024];
BOOL is_root = False;
pstring user_name;
+ pstring machine_gcos_name;
char *remote_machine = NULL;
BOOL add_user = False;
BOOL got_new_pass = False;
BOOL machine_account = False;
+ BOOL disable_user = False;
+ BOOL set_no_password = False;
pstring servicesf = CONFIGFILE;
new_passwd[0] = '\0';
user_name[0] = '\0';
memset(old_passwd, '\0', sizeof(old_passwd));
- memset(new_passwd, '\0', sizeof(old_passwd));
+ memset(new_passwd, '\0', sizeof(new_passwd));
prog_name = argv[0];
@@ -292,16 +408,37 @@ int main(int argc, char **argv)
is_root = (real_uid == 0);
- while ((ch = getopt(argc, argv, "ahr:m:")) != EOF) {
+ while ((ch = getopt(argc, argv, "adhmnr:")) != EOF) {
switch(ch) {
case 'a':
- add_user = True;
+ if(is_root)
+ add_user = True;
+ else
+ usage(prog_name, is_root);
+ break;
+ case 'd':
+ if(is_root) {
+ disable_user = True;
+ got_new_pass = True;
+ strcpy(new_passwd, "XXXXXX");
+ } else
+ usage(prog_name, is_root);
break;
+ case 'n':
+ if(is_root) {
+ set_no_password = True;
+ got_new_pass = True;
+ strcpy(new_passwd, "NO PASSWORD");
+ } else
+ usage(prog_name, is_root);
case 'r':
remote_machine = optarg;
break;
case 'm':
- machine_account = True;
+ if(is_root)
+ machine_account = True;
+ else
+ usage(prog_name, is_root);
break;
case 'h':
default:
@@ -319,14 +456,6 @@ int main(int argc, char **argv)
if(add_user && (remote_machine != NULL))
usage(prog_name, True);
- /*
- * If we are adding a machine account then pretend
- * we already have the new password, we will be using
- * the machinename as the password.
- */
- if(add_user && machine_account)
- got_new_pass = True;
-
if( is_root ) {
/*
@@ -389,6 +518,19 @@ int main(int argc, char **argv)
exit(1);
}
+ /*
+ * If we are adding a machine account then pretend
+ * we already have the new password, we will be using
+ * the machinename as the password.
+ */
+
+ if(add_user && machine_account) {
+ got_new_pass = True;
+ strncpy(new_passwd, user_name, sizeof(fstring));
+ new_passwd[sizeof(fstring)-1] = '\0';
+ strlower(new_passwd);
+ }
+
/*
* If we are root we don't ask for the old password (unless it's on a
* remote machine.
@@ -516,29 +658,37 @@ int main(int argc, char **argv)
if(user_name[username_len] != '$') {
user_name[username_len] = '$';
user_name[username_len+1] = '\0';
- }
+ }
+
+ /*
+ * Setup the pwd struct to point to known
+ * values for a machine account (it doesn't
+ * exist in /etc/passwd).
+ */
+
+ pwd = &machine_account_pwd;
+ pwd->pw_name = user_name;
+ sprintf(machine_gcos_name, "Machine account for %s", user_name);
+ pwd->pw_gecos = machine_gcos_name;
+ pwd->pw_dir = "";
+ pwd->pw_shell = "";
+ pwd->pw_uid = get_machine_uid();
+
}
- /* Calculate the MD4 hash (NT compatible) of the old and new passwords */
- memset(old_nt_p16, '\0', 16);
- E_md4hash((uchar *)old_passwd, old_nt_p16);
+ /* Calculate the MD4 hash (NT compatible) of the new password. */
memset(new_nt_p16, '\0', 16);
E_md4hash((uchar *) new_passwd, new_nt_p16);
- /* Mangle the passwords into Lanman format */
- old_passwd[14] = '\0';
- strupper(old_passwd);
+ /* Mangle the password into Lanman format */
new_passwd[14] = '\0';
strupper(new_passwd);
/*
- * Calculate the SMB (lanman) hash functions of both old and new passwords.
+ * Calculate the SMB (lanman) hash functions of the new password.
*/
- memset(old_p16, '\0', 16);
- E_P16((uchar *) old_passwd, old_p16);
-
memset(new_p16, '\0', 16);
E_P16((uchar *) new_passwd, new_p16);
@@ -580,6 +730,7 @@ int main(int argc, char **argv)
perror(prog_name);
exit(err);
}
+
/* Get the smb passwd entry for this user */
smb_pwent = _my_get_smbpwnam(fp, user_name, &valid_old_pwd,
&got_valid_nt_entry, &seekpos);
@@ -619,19 +770,31 @@ Error was %s\n", prog_name, user_name, pfile, strerror(errno));
if((new_entry = (char *)malloc( new_entry_length )) == 0) {
fprintf(stderr, "%s: Failed to add entry for user %s to file %s. \
Error was %s\n", prog_name, pwd->pw_name, pfile, strerror(errno));
- fclose(fp);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(1);
}
sprintf(new_entry, "%s:%u:", pwd->pw_name, (unsigned)pwd->pw_uid);
p = &new_entry[strlen(new_entry)];
- for( i = 0; i < 16; i++)
- sprintf(&p[i*2], "%02X", new_p16[i]);
- p += 32;
- *p++ = ':';
- for( i = 0; i < 16; i++)
- sprintf(&p[i*2], "%02X", new_nt_p16[i]);
+ if(disable_user) {
+ memcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ p += 32;
+ *p++ = ':';
+ memcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else if (set_no_password) {
+ memcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32);
+ p += 32;
+ *p++ = ':';
+ memcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else {
+ for( i = 0; i < 16; i++)
+ sprintf(&p[i*2], "%02X", new_p16[i]);
+ p += 32;
+ *p++ = ':';
+ for( i = 0; i < 16; i++)
+ sprintf(&p[i*2], "%02X", new_nt_p16[i]);
+ }
p += 32;
*p++ = ':';
sprintf(p, "%s:%s:%s\n", pwd->pw_gecos,
@@ -645,13 +808,13 @@ Error was %s\n", prog_name, pwd->pw_name, pfile, strerror(errno));
Error was %s. Password file may be corrupt ! Please examine by hand !\n",
prog_name, pwd->pw_name, strerror(errno));
}
- fclose(fp);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(1);
}
- fclose(fp);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(0);
}
} else {
@@ -664,14 +827,26 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n",
*/
/* Create the 32 byte representation of the new p16 */
- for (i = 0; i < 16; i++) {
- sprintf(&ascii_p16[i * 2], "%02X", (uchar) new_p16[i]);
+ if(disable_user) {
+ memcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else if (set_no_password) {
+ memcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else {
+ for (i = 0; i < 16; i++) {
+ sprintf(&ascii_p16[i * 2], "%02X", (uchar) new_p16[i]);
+ }
}
if(got_valid_nt_entry) {
/* Add on the NT md4 hash */
ascii_p16[32] = ':';
- for (i = 0; i < 16; i++) {
- sprintf(&ascii_p16[(i * 2)+33], "%02X", (uchar) new_nt_p16[i]);
+ if(disable_user) {
+ memcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else if (set_no_password) {
+ memcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ } else {
+ for (i = 0; i < 16; i++) {
+ sprintf(&ascii_p16[(i * 2)+33], "%02X", (uchar) new_nt_p16[i]);
+ }
}
}
/*
@@ -684,10 +859,10 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n",
err = errno;
fprintf(stderr, "%s: seek fail on file %s.\n",
prog_name, pfile);
- fclose(fp);
errno = err;
perror(prog_name);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(1);
}
/* Sanity check - ensure the character is a ':' */
@@ -695,17 +870,17 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n",
err = errno;
fprintf(stderr, "%s: read fail on file %s.\n",
prog_name, pfile);
- fclose(fp);
errno = err;
perror(prog_name);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(1);
}
if (c != ':') {
fprintf(stderr, "%s: sanity check on passwd file %s failed.\n",
prog_name, pfile);
- fclose(fp);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(1);
}
writelen = (got_valid_nt_entry) ? 65 : 32;
@@ -713,15 +888,19 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n",
err = errno;
fprintf(stderr, "%s: write fail in file %s.\n",
prog_name, pfile);
- fclose(fp);
errno = err;
perror(prog_name);
pw_file_unlock(lockfd);
+ fclose(fp);
exit(err);
}
- fclose(fp);
pw_file_unlock(lockfd);
- printf("Password changed\n");
+ fclose(fp);
+ if(disable_user)
+ printf("User %s disabled.\n", user_name);
+ else if (set_no_password)
+ printf("User %s - set to no password.\n", user_name);
+ else
+ printf("Password changed for user %s.\n", user_name);
return 0;
}
-