ftp.nice.ch/pub/next/unix/disk/SambaManager.1.0.NIHS.s.tar.gz#/SambaManager/samba-1.9.17p4/source/netinfo/smbpasswd.c

This is smbpasswd.c in view mode; [Download] [Up]

/*
 * This is the code to change the samba password in netinfo. It completely 
 * replaces the original samba code. Using -a will change/set the samba/NT
 * as well as the unix password. Otherwise only the samba/NT passwords will 
 * be set. Calling this program as passwd implies -a.
 *
 */

#include "netinfodef.h"

/* The utility routine. */
ni_status ni_search_for_dir(char *dir, char *baseDomain, void **handle, ni_id *id, int timeout, int willwrite, int freeold);

/*
 * Print command usage on stderr and die.
 */
static void usage(char *name)
{
	if ( *name == 's' )
		fprintf(stderr, "Usage is : %s [-a] [username]\n", name);
	else
		fprintf(stderr, "Usage is : %s [username]\n", name);
	exit(1);
}

int main(int argc, char **argv)
{

ni_name  				user_name;
ni_status				status;
ni_id						ndir;
ni_property			prop;
ni_proplist			props;
void						*handle;
char						*ldir;

int							i,j, PropListLen;
int         		real_uid;
int							smb_only = 1;
int							next_arg = 1;
struct passwd		*pwd;

int							passwd_index = -1;
int							smbpasswd_index = -1;
int							smbntpasswd_index = -1;

char 						smbpwd[16];
char 						smbntpwd[16];

fstring         old_passwd;
uchar           old_p16[16];
ni_name					old_unixpasswd;

fstring         new_passwd;
uchar           new_p16[16];
ni_name					new_unixpasswd;
uchar           new_nt_p16[16];
ni_name					new_p32;
ni_name					new_nt_p32;

char           *p;

struct timeval	tp;
struct timezone	tzp;

	/*
	 * Inititialize the strings and character sets.
	 */
	old_unixpasswd = (ni_name)malloc(sizeof(char)*14);
	new_unixpasswd = (ni_name)malloc(sizeof(char)*14);
	new_p32 = (ni_name)malloc(sizeof(char)*34);
	new_nt_p32 = (ni_name)malloc(sizeof(char)*34);
	user_name = (ni_name)malloc(sizeof(char)*256);
	charset_initialise();

	/* Implied -a flag? */
	if ((p = strrchr(argv[0], '/')) != NULL)
		p++;
	else
		p = argv[0];
	
	if ( *p != 's' )
		smb_only = 0;
	else if ((argc > 1) && !strcmp(argv[1],"-a")) {
		smb_only = 0;
		next_arg++;
	}

  /* Get the real uid */
  real_uid = getuid();

  /* If we are root we can change another's password. */
  if (real_uid == 0) { 
    if ((argc - next_arg) > 1)
      usage(argv[0]);
		if (next_arg < argc) {
			i = (strlen(argv[next_arg]) < 255)?strlen(argv[next_arg]):255;
    	(void)strncpy(user_name, argv[next_arg], i);
    	user_name[i] = '\0';
		} else
			(void)strcpy(user_name, "root");
  } else {
		if (argc - next_arg)
    	usage(argv[0]);
    pwd = getpwuid(real_uid);
	  if (pwd == NULL) {
	    fprintf(stderr, "%s: Unable to get UNIX password entry.\n", argv[0]);
	    exit(1);
	  }
		(void)strncpy(user_name, pwd->pw_name, strlen(pwd->pw_name)+1);
	}





	/*
	 * Find the user's entry in NetInfo. We will use the first entry found
	 * in the hierarchy.
	 */
	 
	/* Set the directory to get. */
	ldir = (char *)malloc(sizeof(char)*(8+strlen(user_name)));
	(void)strcpy(ldir, "/users/");
	(void)strcat(ldir, user_name);
	
	/*
	 * Scan the NetInfo hierarchy, starting from the local level,
	 * until either an entry is found or we are past the top level.
	 */
	handle = NULL;
	status = ni_search_for_dir(ldir, ".", &handle, &ndir, 5, 1, 1);
	free(ldir);

	if (status != NI_OK) {
    fprintf(stderr, "%s: Unable to connect to NetInfo.\n", argv[0]);
		exit(1);
	}

	/*
	 * Set the sesson to this user unless we are root.
	 */
	 if (real_uid != 0) {
		status = ni_setuser(handle, user_name);
		if (status != NI_OK) {
			fprintf(stderr, "%s: Unable to set the user to %s.\n", argv[0], user_name);
			ni_free(handle);
			exit(1);
		}
	}

	/* Read the directory and all its properties, set the indexes of all entries. */
	status = ni_read(handle, &ndir, &props);
	if (status != NI_OK) {
		ni_free(handle);
		fprintf(stderr, "%s: Unable to get netinfo entry for user %s.\n", argv[0], user_name);
		exit(1);
	}			

#define PWENTNAME(pos) 	props.ni_proplist_val[pos].nip_name
#define PWENTVALU(pos) 	(props.ni_proplist_val[pos].nip_val.ni_namelist_len>0)? \
                          props.ni_proplist_val[pos].nip_val.ni_namelist_val[0]:""

	*smbpwd = '\0';
	*smbntpwd = '\0';

	for (i = 0; i < props.ni_proplist_len; i++) {
		if (!strcmp(PWENTNAME(i), S_PASSWD))
			passwd_index = i;
		else if (!strcmp(PWENTNAME(i), S_SMBPASSWD)) {
			smbpasswd_index = i;
			/*
					If the password starts with 'X' or '*', the entry has been disabled. 
					If it starts with NO PASSWORD, then no password is required.
					If it starts with the user's name, then no old password is required.
			*/
			if ((*(PWENTVALU(i)) == '*') || (*(PWENTVALU(i)) == 'X')) {
				strncpy((char *)smbpwd, PWENTVALU(i), sizeof(smbpwd)-1);
				smbpwd[sizeof(smbpwd)-1] = '\0';
			} else if (strncasecmp(PWENTVALU(i), "NO PASSWORD", 11) &&
								 strncmp(PWENTVALU(i), user_name, strlen(user_name)))
				ni_decrypt(PWENTVALU(i), (char *)smbpwd);
		} else if (!strcmp(PWENTNAME(i), S_SMBNTPASSWD)) {
			smbntpasswd_index = i;
		}
#ifdef TEST		
		printf("property: %-24s", PWENTNAME(i));
		for (j = 0; j < props.ni_proplist_val[i].nip_val.ni_namelist_len; j++)
			printf("%s%s", j>0?",":"", props.ni_proplist_val[i].nip_val.ni_namelist_val[j]);
		printf("\n");
#endif
	}

	ni_proplist_free(&props);
	
	/* Start the dialog. */
	printf("Changing%s for %s.\n", smb_only?" samba password":" passwords", user_name);

		
	
  /* 
	 * If we are root or the old smb password starts with 'NO PASSWORD'
	 * or dosn't exist, (*smbpwd == '\0'), and the unix password
	 * isn't to be set we don't ask for the old password.
	 */
	 
#ifdef TEST
  printf("real_uid: %d\n",real_uid);
	printf("smb_only: %d\n",smb_only);
#endif
	 
  old_passwd[0] = '\0';
//  if ((real_uid != 0) && ((*smbpwd != '\0') || !smb_only)) {
  if (real_uid) {
		p = getpass("Unix password:");
		strncpy(old_passwd, p, sizeof(fstring));
		old_passwd[sizeof(fstring)-1] = '\0';
		/* Encrypt the unix password. */
		strncpy(new_unixpasswd, pwd->pw_passwd, 2);	/* copy the old salt */
		new_unixpasswd[2] = '\0';
		memset(old_unixpasswd, '\0', 14);
		strncpy(old_unixpasswd, crypt(old_passwd, new_unixpasswd), 13);

		/* Bail out if the old password isn't identical to the stored one. */
		if (memcmp(old_unixpasswd, pwd->pw_passwd, strlen(old_unixpasswd))) {
			ni_free(handle);
			printf("Sorry.\n");
			exit(1);
		}
		status = ni_setpassword(handle, old_passwd);
		if (status != NI_OK) {
			fprintf(stderr, "%s: Unable to set the password of user%s.\n", argv[0], user_name);
			ni_free(handle);
			exit(1);
		}
	}
	

	/* 
	 *Get a new password and verify.
	 */
	new_passwd[0] = '\0';
	if (!smb_only)
		p = getpass("New password:");
	else
		p = getpass("New samba password:");

	while ((*p != '\0') && (strlen(p) < 6)) {
		fprintf(stderr, "Please use a longer password.\n", argv[0]);
		p = getpass("New password:");
	}

	strncpy(new_passwd, p, sizeof(fstring));
	new_passwd[sizeof(fstring)-1] = '\0';

  if (new_passwd[0] == '\0') {
    printf("Password unchanged\n");
		ni_free(handle);
    exit(1);
  }

	if (!smb_only)
		p = getpass("Retype new password:");
	else
		p = getpass("Retype new samba password:");
	if (strncmp(p, new_passwd, sizeof(fstring)-1)) {
		fprintf(stderr, "%s: Mismatch - passwords unchanged.\n", argv[0]);
		ni_free(handle);
		exit(1);
	}

	/*
	 * The new password has been verified. If we have to set the unix password,
	 * pick a new salt, then encrypt. Encrypt the samba passwords.
	 */
	 
 	if (!smb_only) {
	char	sa[64] = {'a','b','c','d','e','f','g','h','i','j','k','l','m',
									'n','o','p','q','r','s','t','u','v','w','x','y','z',
									'A','B','C','D','E','F','G','H','I','J','K','L','M',
									'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
									'0','1','2','3','4','5','6','7','8','9','.','/'},
				salt[3];
	
		/* Have to pick a new salt! */
		if (gettimeofday(&tp, &tzp) != 0) {
			perror(argv[0]);
			ni_free(handle);
			exit(1);
		}
		
		(void) srandom(tp.tv_sec);
		salt[0] = sa[random()%54];
		salt[1] = sa[random()%54];
		salt[2] = '\0';
		
		
  	memset(new_unixpasswd, '\0', 14);
		strncpy(new_unixpasswd, crypt(new_passwd, salt), 13);
	}
	
  memset(new_nt_p16, '\0', 16);
  E_md4hash((uchar *) new_passwd, new_nt_p16);
  
  /* Mangle the passwords into Lanman format */
  new_passwd[14] = '\0';
  strupper(new_passwd);

  /*
   * Calculate the SMB (lanman) hash functions of new password.
   */  
  memset(new_p16, '\0', 16);
  E_P16((uchar *) new_passwd, new_p16);


  /*
   * If we get here either we were root or the old password checked out
   * ok.
   */

  /* Create the 32 byte representation of the new p16 */
	ni_encrypt(new_p16, new_p32);

  /* Create the 32 byte representation of the new NT md4 hash */
	ni_encrypt(new_nt_p16, new_nt_p32);

#ifdef TEST
	if (!smb_only)
		printf("New unix password (encrypted) : %s\n",new_unixpasswd);
	printf("New samba password (encrypted): %s\n", new_p32);
	printf("New NT password (encrypted)   : %s\n", new_nt_p32);
#endif

	/* 
	 * Now write (back) to NetInfo. As the session password may have been set,
	 * we must write the unix password last! 
	 * If the samba password entries don't exist and we are root, create them!
	 */	
	
	PropListLen = props.ni_proplist_len;

	prop.nip_val.ni_namelist_len = 1;
	prop.nip_val.ni_namelist_val = &new_p32;

	if (smbpasswd_index >= 0) 
		status = ni_writeprop(handle, &ndir, smbpasswd_index, prop.nip_val); 
	else {
		prop.nip_name = S_SMBPASSWD;
		status = ni_createprop(handle, &ndir, prop, PropListLen++);
		if (status == NI_OK) {
			prop.nip_val.ni_namelist_len = 1;
			prop.nip_val.ni_namelist_val = &user_name;
			prop.nip_name = S_SMBPASSWDW;
			status = ni_createprop(handle, &ndir, prop, PropListLen++);
		}
	}
	
	if (status == NI_OK) {
		prop.nip_val.ni_namelist_len = 1;
		prop.nip_val.ni_namelist_val = &new_nt_p32;
	
		if (smbntpasswd_index >= 0)
			status = ni_writeprop(handle, &ndir, smbntpasswd_index, prop.nip_val); 
		else {
			prop.nip_name = S_SMBNTPASSWD;
			status = ni_createprop(handle, &ndir, prop, PropListLen++);
			if (status == NI_OK) {
				prop.nip_val.ni_namelist_len = 1;
				prop.nip_val.ni_namelist_val = &user_name;
				prop.nip_name = S_SMBNTPASSWDW;
				status = ni_createprop(handle, &ndir, prop, PropListLen++);
			}
		}
	}

 	if ((status == NI_OK) && (!smb_only) && (passwd_index >= 0)) {
		prop.nip_val.ni_namelist_len = 1;
		prop.nip_val.ni_namelist_val = &new_unixpasswd;
		status = ni_writeprop(handle, &ndir, passwd_index, prop.nip_val); 
	}
	
	if (status != NI_OK) {
		fprintf(stderr, "%s: Unable to write to NetInfo.\n", argv[0]);
		ni_free(handle);
		return 1;
	}

	ni_free(handle);
	return 0;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.