示例#1
0
文件: pdbedit.c 项目: Gazzonyx/samba
static int set_machine_info(const char *machinename,
			    const char *account_control,
			    const char *machine_sid)
{
	struct samu *sam_pwent = NULL;
	TALLOC_CTX *tosctx;
	uint32_t acb_flags;
	uint32_t not_settable;
	uint32_t new_flags;
	struct dom_sid m_sid;
	char *name;
	int len;
	bool ret;

	len = strlen(machinename);
	if (len == 0) {
		fprintf(stderr, "No machine name given\n");
		return -1;
	}

	tosctx = talloc_tos();
	if (!tosctx) {
		fprintf(stderr, "Out of memory!\n");
		return -1;
	}

	sam_pwent = samu_new(tosctx);
	if (!sam_pwent) {
		return 1;
	}

	if (machinename[len-1] == '$') {
		name = talloc_strdup(sam_pwent, machinename);
	} else {
		name = talloc_asprintf(sam_pwent, "%s$", machinename);
	}
	if (!name) {
		fprintf(stderr, "Out of memory!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (!strlower_m(name)) {
		fprintf(stderr, "strlower_m %s failed\n", name);
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	ret = pdb_getsampwnam(sam_pwent, name);
	if (!ret) {
		fprintf (stderr, "Username not found!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (account_control) {
		not_settable = ~(ACB_DISABLED);

		new_flags = pdb_decode_acct_ctrl(account_control);

		if (new_flags & not_settable) {
			fprintf(stderr, "Can only set [D] flags\n");
			TALLOC_FREE(sam_pwent);
			return -1;
		}

		acb_flags = pdb_get_acct_ctrl(sam_pwent);

		pdb_set_acct_ctrl(sam_pwent,
				  (acb_flags & not_settable) | new_flags,
				  PDB_CHANGED);
	}
	if (machine_sid) {
		if (get_sid_from_cli_string(&m_sid, machine_sid)) {
			fprintf(stderr, "Failed to parse SID\n");
			return -1;
		}
		pdb_set_user_sid(sam_pwent, &m_sid, PDB_CHANGED);
	}

	if (NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
		print_user_info(name, True, False);
	} else {
		fprintf (stderr, "Unable to modify entry!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}
	TALLOC_FREE(sam_pwent);
	return 0;
}
示例#2
0
文件: pdbedit.c 项目: Gazzonyx/samba
static int set_user_info(const char *username, const char *fullname,
			 const char *homedir, const char *acct_desc,
			 const char *drive, const char *script,
			 const char *profile, const char *account_control,
			 const char *user_sid, const char *user_domain,
			 const bool badpw, const bool hours,
			 const char *kickoff_time)
{
	bool updated_autolock = False, updated_badpw = False;
	struct samu *sam_pwent;
	uint8_t hours_array[MAX_HOURS_LEN];
	uint32_t hours_len;
	uint32_t acb_flags;
	uint32_t not_settable;
	uint32_t new_flags;
	struct dom_sid u_sid;
	bool ret;

	sam_pwent = samu_new(NULL);
	if (!sam_pwent) {
		return 1;
	}

	ret = pdb_getsampwnam(sam_pwent, username);
	if (!ret) {
		fprintf (stderr, "Username not found!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (hours) {
		hours_len = pdb_get_hours_len(sam_pwent);
		memset(hours_array, 0xff, hours_len);

		pdb_set_hours(sam_pwent, hours_array, hours_len, PDB_CHANGED);
	}

	if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
		DEBUG(2,("pdb_update_autolock_flag failed.\n"));
	}

	if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
		DEBUG(2,("pdb_update_bad_password_count failed.\n"));
	}

	if (fullname)
		pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
	if (acct_desc)
		pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
	if (homedir)
		pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
	if (drive)
		pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
	if (script)
		pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
	if (profile)
		pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
	if (user_domain)
		pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);

	if (account_control) {
		not_settable = ~(ACB_DISABLED | ACB_HOMDIRREQ |
				 ACB_PWNOTREQ | ACB_PWNOEXP | ACB_AUTOLOCK);

		new_flags = pdb_decode_acct_ctrl(account_control);

		if (new_flags & not_settable) {
			fprintf(stderr, "Can only set [NDHLX] flags\n");
			TALLOC_FREE(sam_pwent);
			return -1;
		}

		acb_flags = pdb_get_acct_ctrl(sam_pwent);

		pdb_set_acct_ctrl(sam_pwent,
				  (acb_flags & not_settable) | new_flags,
				  PDB_CHANGED);
	}
	if (user_sid) {
		if (get_sid_from_cli_string(&u_sid, user_sid)) {
			fprintf(stderr, "Failed to parse SID\n");
			return -1;
		}
		pdb_set_user_sid(sam_pwent, &u_sid, PDB_CHANGED);
	}

	if (badpw) {
		pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
	}

	if (kickoff_time) {
		char *endptr;
		time_t value = get_time_t_max();

		if (strcmp(kickoff_time, "never") != 0) {
			uint32_t num = strtoul(kickoff_time, &endptr, 10);

			if ((endptr == kickoff_time) || (endptr[0] != '\0')) {
				fprintf(stderr, "Failed to parse kickoff time\n");
				return -1;
			}

			value = convert_uint32_t_to_time_t(num);
		}

		pdb_set_kickoff_time(sam_pwent, value, PDB_CHANGED);
	}

	if (NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
		print_user_info(username, True, False);
	} else {
		fprintf (stderr, "Unable to modify entry!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}
	TALLOC_FREE(sam_pwent);
	return 0;
}
示例#3
0
/************************************************************************
 makes a struct sam_passwd from a NIS+ object.
 ************************************************************************/
static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, nis_object *obj)
{
  char *ptr;
  pstring full_name;    /* this must be translated to dos code page */
  pstring acct_desc;    /* this must be translated to dos code page */
  pstring home_dir;     /* set default value from smb.conf for user */
  pstring home_drive;   /* set default value from smb.conf for user */
  pstring logon_script; /* set default value from smb.conf for user */
  pstring profile_path; /* set default value from smb.conf for user */
  pstring hours;
  int hours_len;
  unsigned char smbpwd[16];
  unsigned char smbntpwd[16];
  

  /*
   * time values. note: this code assumes 32bit time_t!
   */

  pdb_set_logon_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_LOGON_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_logoff_time(pw_buf, get_time_t_max());
  ptr = ENTRY_VAL(obj, NPF_LOGOFF_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_kickoff_time(pw_buf, get_time_t_max());
  ptr = ENTRY_VAL(obj, NPF_KICK_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_pass_last_set_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_PWDLSET_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }
  
  pdb_set_pass_can_change_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_PWDCCHG_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }
  
  pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
  ptr = ENTRY_VAL(obj, NPF_PWDMCHG_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  /* string values */
  pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
  pdb_set_domain(pw_buf, lp_workgroup());
  /* pdb_set_nt_username() -- cant set it here... */

  get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
  unix_to_dos(full_name);
  pdb_set_fullname(pw_buf, full_name);

  pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
							   NPF_ACB)));

  get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
  unix_to_dos(acct_desc);
  pdb_set_acct_desc(pw_buf, acct_desc);

  pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
  pdb_set_munged_dial(pw_buf, NULL);

/* Might want to consult sys_getpwnam for the following two.
  for now, use same default as pdb_fill-default_sam */

  ptr = ENTRY_VAL(obj, NPF_UID);
  pdb_set_uid(pw_buf, ptr ? atoi(ptr) : -1);

  ptr = ENTRY_VAL(obj, NPF_SMB_GRPID);
  pdb_set_gid(pw_buf, ptr ? atoi(ptr) : -1);


  ptr = ENTRY_VAL(obj, NPF_USER_RID); 
  pdb_set_user_rid(pw_buf, ptr ? atoi(ptr) : 
	pdb_uid_to_user_rid(pdb_get_uid(pw_buf)));

  ptr = ENTRY_VAL(obj, NPF_GROUP_RID);
  pdb_set_group_rid(pw_buf, ptr ? atoi(ptr) :
	pdb_gid_to_group_rid(pdb_get_gid(pw_buf)));


  /* values, must exist for user */
  if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
    /* FIXME!!  This doesn't belong here. 
       Should be set in net_sam_logon() 
       --jerry */
    pstrcpy(samlogon_user, pdb_get_username(pw_buf));
    
    get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
    if( !(home_dir && *home_dir) ) {
      pstrcpy(home_dir, lp_logon_home());
      pdb_set_homedir(pw_buf, home_dir, False);
    }
    else
      pdb_set_homedir(pw_buf, home_dir, True);

    get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
    if( !(home_drive && *home_drive) ) {
      pstrcpy(home_drive, lp_logon_drive());
      pdb_set_dir_drive(pw_buf, home_drive, False);
    }
    else
      pdb_set_dir_drive(pw_buf, home_drive, True);

    get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
			 sizeof(pstring));
    if( !(logon_script && *logon_script) ) {
      pstrcpy(logon_script, lp_logon_script());
      pdb_set_logon_script(pw_buf, logon_script, False);
    }
    else
      pdb_set_logon_script(pw_buf, logon_script, True);

    get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
    if( !(profile_path && *profile_path) ) {
      pstrcpy(profile_path, lp_logon_path());
      pdb_set_profile_path(pw_buf, profile_path, False);
    }
    else
      pdb_set_profile_path(pw_buf, profile_path, True);

  } 
  else 
  {
    /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
    pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS); 
  }

  /* Check the lanman password column. */
  ptr = ENTRY_VAL(obj, NPF_LMPWD);
  if (!pdb_set_lanman_passwd(pw_buf, NULL))
	return False;

  if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
    pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
  } else {
    if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
      DEBUG(0, ("malformed LM pwd entry: %s.\n",
		pdb_get_username(pw_buf)));
      return False;
    } 
    if (!pdb_set_lanman_passwd(pw_buf, smbpwd))
		return False;
  }
  
  /* Check the NT password column. */
  ptr = ENTRY_VAL(obj, NPF_NTPWD);
  if (!pdb_set_nt_passwd(pw_buf, NULL))
	return False;
  
  if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
      strncasecmp(ptr, "NO PASSWORD", 11)) {
    if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
      DEBUG(0, ("malformed NT pwd entry:\
 uid = %d.\n",
		pdb_get_uid(pw_buf)));
      return False;
    }
    if (!pdb_set_nt_passwd(pw_buf, smbntpwd))
		return False;
  }
示例#4
0
/*
 *	mschap_authenticate() - authenticate user based on given
 *	attributes and configuration.
 *	We will try to find out password in configuration
 *	or in configured passwd file.
 *	If one is found we will check paraneters given by NAS.
 *
 *	If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
 *	one of:
 *		PAP:      PW_USER_PASSWORD or
 *		MS-CHAP:  PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
 *		MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
 *	In case of password mismatch or locked account we MAY return
 *	PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
 *	If MS-CHAP2 succeeds we MUST return
 *	PW_MSCHAP2_SUCCESS
 */
static int mschap_authenticate(void * instance, REQUEST *request)
{
#define inst ((rlm_mschap_t *)instance)
	VALUE_PAIR *challenge = NULL;
	VALUE_PAIR *response = NULL;
	VALUE_PAIR *password = NULL;
	VALUE_PAIR *lm_password, *nt_password, *smb_ctrl;
	VALUE_PAIR *username;
	uint8_t nthashhash[16];
	char msch2resp[42];
	char *username_string;
	int chap = 0;
	int		do_ntlm_auth;

	/*
	 *	If we have ntlm_auth configured, use it unless told
	 *	otherwise
	 */
	do_ntlm_auth = (inst->ntlm_auth != NULL);

	/*
	 *	If we have an ntlm_auth configuration, then we may
	 *	want to suppress it.
	 */
	if (do_ntlm_auth) {
		VALUE_PAIR *vp = pairfind(request->config_items,
					  PW_MS_CHAP_USE_NTLM_AUTH);
		if (vp) do_ntlm_auth = vp->vp_integer;
	}

	/*
	 *	Find the SMB-Account-Ctrl attribute, or the
	 *	SMB-Account-Ctrl-Text attribute.
	 */
	smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
	if (!smb_ctrl) {
		password = pairfind(request->config_items,
				    PW_SMB_ACCOUNT_CTRL_TEXT);
		if (password) {
			smb_ctrl = radius_pairmake(request,
						   &request->config_items,
						   "SMB-Account-CTRL", "0",
						   T_OP_SET);
			if (smb_ctrl) {
				smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
			}
		}
	}

	/*
	 *	We're configured to do MS-CHAP authentication.
	 *	and account control information exists.  Enforce it.
	 */
	if (smb_ctrl) {
		/*
		 *	Password is not required.
		 */
		if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
			RDEBUG2("SMB-Account-Ctrl says no password is required.");
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Decide how to get the passwords.
	 */
	password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD);

	/*
	 *	We need an LM-Password.
	 */
	lm_password = pairfind(request->config_items, PW_LM_PASSWORD);
	if (lm_password) {
		/*
		 *	Allow raw octets.
		 */
		if ((lm_password->length == 16) ||
		    ((lm_password->length == 32) &&
		     (fr_hex2bin(lm_password->vp_strvalue,
				 lm_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found LM-Password");
			lm_password->length = 16;

		} else {
			radlog_request(L_ERR, 0, request, "Invalid LM-Password");
			lm_password = NULL;
		}

	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create LM-Password.");

	} else {		/* there is a configured Cleartext-Password */
		lm_password = radius_pairmake(request, &request->config_items,
					      "LM-Password", "", T_OP_EQ);
		if (!lm_password) {
			radlog_request(L_ERR, 0, request, "No memory");
		} else {
			smbdes_lmpwdhash(password->vp_strvalue,
					 lm_password->vp_octets);
			lm_password->length = 16;
		}
	}

	/*
	 *	We need an NT-Password.
	 */
	nt_password = pairfind(request->config_items, PW_NT_PASSWORD);
	if (nt_password) {
		if ((nt_password->length == 16) ||
		    ((nt_password->length == 32) &&
		     (fr_hex2bin(nt_password->vp_strvalue,
				 nt_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found NT-Password");
			nt_password->length = 16;

                } else {
			radlog_request(L_ERR, 0, request, "Invalid NT-Password");
			nt_password = NULL;
		}
	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create NT-Password.");

	} else {		/* there is a configured Cleartext-Password */
		nt_password = radius_pairmake(request, &request->config_items,
					      "NT-Password", "", T_OP_EQ);
		if (!nt_password) {
			radlog_request(L_ERR, 0, request, "No memory");
			return RLM_MODULE_FAIL;
		} else {
			ntpwdhash(nt_password->vp_octets,
				  password->vp_strvalue);
			nt_password->length = 16;
		}
	}

	challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
	if (!challenge) {
		RDEBUG2("No MS-CHAP-Challenge in the request");
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We also require an MS-CHAP-Response.
	 */
	response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);

	/*
	 *	MS-CHAP-Response, means MS-CHAPv1
	 */
	if (response) {
		int offset;

		/*
		 *	MS-CHAPv1 challenges are 8 octets.
		 */
		if (challenge->length < 8) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We are doing MS-CHAP.  Calculate the MS-CHAP
		 *	response
		 */
		if (response->vp_octets[1] & 0x01) {
			RDEBUG2("Told to do MS-CHAPv1 with NT-Password");
			password = nt_password;
			offset = 26;
		} else {
			RDEBUG2("Told to do MS-CHAPv1 with LM-Password");
			password = lm_password;
			offset = 2;
		}

		/*
		 *	Do the MS-CHAP authentication.
		 */
		if (do_mschap(inst, request, password, challenge->vp_octets,
			      response->vp_octets + offset, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("MS-CHAP-Response is incorrect.");
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets,
					 "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_REJECT;
		}

		chap = 1;

	} else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
		uint8_t	mschapv1_challenge[16];

		/*
		 *	MS-CHAPv2 challenges are 16 octets.
		 */
		if (challenge->length < 16) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We also require a User-Name
		 */
		username = pairfind(request->packet->vps, PW_USER_NAME);
		if (!username) {
			radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2");
			return RLM_MODULE_INVALID;
		}


		/*
		 *	with_ntdomain_hack moved here
		 */
		if ((username_string = strchr(username->vp_strvalue, '\\')) != NULL) {
		        if (inst->with_ntdomain_hack) {
			        username_string++;
			} else {
				RDEBUG2("  NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
				username_string = username->vp_strvalue;
			}
		} else {
		        username_string = username->vp_strvalue;
		}

#ifdef __APPLE__
		/*
		 *  No "known good" NT-Password attribute.  Try to do
		 *  OpenDirectory authentication.
		 *
		 *  If OD determines the user is an AD user it will return noop, which
		 *  indicates the auth process should continue directly to AD.
		 *  Otherwise OD will determine auth success/fail.
		 */
		if (!nt_password && inst->open_directory) {
			RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication.");
			int odStatus = od_mschap_auth(request, challenge, username);
			if (odStatus != RLM_MODULE_NOOP) {
				return odStatus;
			}
		}
#endif
		/*
		 *	The old "mschapv2" function has been moved to
		 *	here.
		 *
		 *	MS-CHAPv2 takes some additional data to create an
		 *	MS-CHAPv1 challenge, and then does MS-CHAPv1.
		 */
		challenge_hash(response->vp_octets + 2, /* peer challenge */
			       challenge->vp_octets, /* our challenge */
			       username_string,	/* user name */
			       mschapv1_challenge); /* resulting challenge */

		RDEBUG2("Told to do MS-CHAPv2 for %s with NT-Password",
		       username_string);

		if (do_mschap(inst, request, nt_password, mschapv1_challenge,
			      response->vp_octets + 26, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets,
					 "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	Get the NT-hash-hash, if necessary
		 */
		if (nt_password) {
		}

		auth_response(username_string, /* without the domain */
			      nthashhash, /* nt-hash-hash */
			      response->vp_octets + 26, /* peer response */
			      response->vp_octets + 2, /* peer challenge */
			      challenge->vp_octets, /* our challenge */
			      msch2resp); /* calculated MPPE key */
		mschap_add_reply(request, &request->reply->vps, *response->vp_octets,
				 "MS-CHAP2-Success", msch2resp, 42);
		chap = 2;

	} else {		/* Neither CHAPv1 or CHAPv2 response: die */
		radlog_request(L_AUTH, 0, request, "No MS-CHAP response found");
		return RLM_MODULE_INVALID;
	}

	/*
	 *	We have a CHAP response, but the account may be
	 *	disabled.  Reject the user with the same error code
	 *	we use when their password is invalid.
	 */
	if (smb_ctrl) {
		/*
		 *	Account is disabled.
		 *
		 *	They're found, but they don't exist, so we
		 *	return 'not found'.
		 */
		if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
		    ((smb_ctrl->vp_integer & ACB_NORMAL) == 0)) {
			RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal account.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_NOTFOUND;
		}

		/*
		 *	User is locked out.
		 */
		if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
			RDEBUG2("SMB-Account-Ctrl says that the account is locked out.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=647 R=0", 9);
			return RLM_MODULE_USERLOCK;
		}
	}

	/* now create MPPE attributes */
	if (inst->use_mppe) {
		uint8_t mppe_sendkey[34];
		uint8_t mppe_recvkey[34];

		if (chap == 1){
			RDEBUG2("adding MS-CHAPv1 MPPE keys");
			memset(mppe_sendkey, 0, 32);
			if (lm_password) {
				memcpy(mppe_sendkey, lm_password->vp_octets, 8);
			}

			/*
			 *	According to RFC 2548 we
			 *	should send NT hash.  But in
			 *	practice it doesn't work.
			 *	Instead, we should send nthashhash
			 *
			 *	This is an error on RFC 2548.
			 */
			/*
			 *	do_mschap cares to zero nthashhash if NT hash
			 *	is not available.
			 */
			memcpy(mppe_sendkey + 8,
			       nthashhash, 16);
			mppe_add_reply(request,
				       "MS-CHAP-MPPE-Keys",
				       mppe_sendkey, 32);
		} else if (chap == 2) {
			RDEBUG2("adding MS-CHAPv2 MPPE keys");
			mppe_chap2_gen_keys128(nthashhash,
					       response->vp_octets + 26,
					       mppe_sendkey, mppe_recvkey);

			mppe_add_reply(request,
				       "MS-MPPE-Recv-Key",
				       mppe_recvkey, 16);
			mppe_add_reply(request,
				       "MS-MPPE-Send-Key",
				       mppe_sendkey, 16);

		}
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Policy",
				(inst->require_encryption)? "0x00000002":"0x00000001",
				T_OP_EQ);
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Types",
				(inst->require_strong)? "0x00000004":"0x00000006",
				T_OP_EQ);
	} /* else we weren't asked to use MPPE */

	return RLM_MODULE_OK;
#undef inst
}
/*
 *	mschap_authenticate() - authenticate user based on given
 *	attributes and configuration.
 *	We will try to find out password in configuration
 *	or in configured passwd file.
 *	If one is found we will check paraneters given by NAS.
 *
 *	If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
 *	one of:
 *		PAP:      PW_USER_PASSWORD or
 *		MS-CHAP:  PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
 *		MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
 *	In case of password mismatch or locked account we MAY return
 *	PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
 *	If MS-CHAP2 succeeds we MUST return
 *	PW_MSCHAP2_SUCCESS
 */
static int mschap_authenticate(void * instance, REQUEST *request)
{
#define inst ((rlm_mschap_t *)instance)
	VALUE_PAIR *challenge = NULL;
	VALUE_PAIR *response = NULL;
	VALUE_PAIR *password = NULL;
	VALUE_PAIR *lm_password, *nt_password, *smb_ctrl;
	VALUE_PAIR *username;
	uint8_t nthashhash[16];
	char msch2resp[42];
	char *username_string;
	int chap = 0;
	int		do_ntlm_auth;

	/*
	 *	If we have ntlm_auth configured, use it unless told
	 *	otherwise
	 */
	do_ntlm_auth = (inst->ntlm_auth != NULL);

	/*
	 *	If we have an ntlm_auth configuration, then we may
	 *	want to suppress it.
	 */
	if (do_ntlm_auth) {
		VALUE_PAIR *vp = pairfind(request->config_items,
					  PW_MS_CHAP_USE_NTLM_AUTH);
		if (vp) do_ntlm_auth = vp->vp_integer;
	}

	/*
	 *	Find the SMB-Account-Ctrl attribute, or the
	 *	SMB-Account-Ctrl-Text attribute.
	 */
	smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
	if (!smb_ctrl) {
		password = pairfind(request->config_items,
				    PW_SMB_ACCOUNT_CTRL_TEXT);
		if (password) {
			smb_ctrl = radius_pairmake(request,
						   &request->config_items,
						   "SMB-Account-CTRL", "0",
						   T_OP_SET);
			if (smb_ctrl) {
				smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
			}
		}
	}

	/*
	 *	We're configured to do MS-CHAP authentication.
	 *	and account control information exists.  Enforce it.
	 */
	if (smb_ctrl) {
		/*
		 *	Password is not required.
		 */
		if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
			RDEBUG2("SMB-Account-Ctrl says no password is required.");
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Decide how to get the passwords.
	 */
	password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD);

	/*
	 *	We need an LM-Password.
	 */
	lm_password = pairfind(request->config_items, PW_LM_PASSWORD);
	if (lm_password) {
		/*
		 *	Allow raw octets.
		 */
		if ((lm_password->length == 16) ||
		    ((lm_password->length == 32) &&
		     (fr_hex2bin(lm_password->vp_strvalue,
				 lm_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found LM-Password");
			lm_password->length = 16;

		} else {
			radlog_request(L_ERR, 0, request, "Invalid LM-Password");
			lm_password = NULL;
		}

	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create LM-Password.");

	} else {		/* there is a configured Cleartext-Password */
		lm_password = radius_pairmake(request, &request->config_items,
					      "LM-Password", "", T_OP_EQ);
		if (!lm_password) {
			radlog_request(L_ERR, 0, request, "No memory");
		} else {
			smbdes_lmpwdhash(password->vp_strvalue,
					 lm_password->vp_octets);
			lm_password->length = 16;
		}
	}

	/*
	 *	We need an NT-Password.
	 */
	nt_password = pairfind(request->config_items, PW_NT_PASSWORD);
	if (nt_password) {
		if ((nt_password->length == 16) ||
		    ((nt_password->length == 32) &&
		     (fr_hex2bin(nt_password->vp_strvalue,
				 nt_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found NT-Password");
			nt_password->length = 16;

                } else {
			radlog_request(L_ERR, 0, request, "Invalid NT-Password");
			nt_password = NULL;
		}
	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create NT-Password.");

	} else {		/* there is a configured Cleartext-Password */
		nt_password = radius_pairmake(request, &request->config_items,
					      "NT-Password", "", T_OP_EQ);
		if (!nt_password) {
			radlog_request(L_ERR, 0, request, "No memory");
			return RLM_MODULE_FAIL;
		} else {
			mschap_ntpwdhash(nt_password->vp_octets,
				  password->vp_strvalue);
			nt_password->length = 16;
		}
	}

	challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
	if (!challenge) {
		RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We also require an MS-CHAP-Response.
	 */
	response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);

	/*
	 *	MS-CHAP-Response, means MS-CHAPv1
	 */
	if (response) {
		int offset;

		/*
		 *	MS-CHAPv1 challenges are 8 octets.
		 */
		if (challenge->length < 8) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We are doing MS-CHAP.  Calculate the MS-CHAP
		 *	response
		 */
		if (response->vp_octets[1] & 0x01) {
			RDEBUG2("Client is using MS-CHAPv1 with NT-Password");
			password = nt_password;
			offset = 26;
		} else {
			RDEBUG2("Client is using MS-CHAPv1 with LM-Password");
			password = lm_password;
			offset = 2;
		}

		/*
		 *	Do the MS-CHAP authentication.
		 */
		if (do_mschap(inst, request, password, challenge->vp_octets,
			      response->vp_octets + offset, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("MS-CHAP-Response is incorrect.");
			goto do_error;
		}

		chap = 1;

	} else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
		uint8_t	mschapv1_challenge[16];
		VALUE_PAIR *name_attr, *response_name;

		/*
		 *	MS-CHAPv2 challenges are 16 octets.
		 */
		if (challenge->length < 16) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We also require a User-Name
		 */
		username = pairfind(request->packet->vps, PW_USER_NAME);
		if (!username) {
			radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2");
			return RLM_MODULE_INVALID;
		}

		/*
		 *      Check for MS-CHAP-User-Name and if found, use it
		 *      to construct the MSCHAPv1 challenge.  This is
		 *      set by rlm_eap_mschap to the MS-CHAP Response
		 *      packet Name field.
		 *
		 *	We prefer this to the User-Name in the
		 *	packet.
		 */
		response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
		if (response_name) {
			name_attr = response_name;
		} else {
			name_attr = username;
		}
		
		/*
		 *	with_ntdomain_hack moved here, too.
		 */
		if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
			if (inst->with_ntdomain_hack) {
				username_string++;
			} else {
				RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
				username_string = name_attr->vp_strvalue;
			}
		} else {
			username_string = name_attr->vp_strvalue;
		}
		
		if (response_name &&
		    ((username->length != response_name->length) ||
		     (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
			RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	The old "mschapv2" function has been moved to
		 *	here.
		 *
		 *	MS-CHAPv2 takes some additional data to create an
		 *	MS-CHAPv1 challenge, and then does MS-CHAPv1.
		 */
		RDEBUG2("Creating challenge hash with username: %s",
			username_string);
		mschap_challenge_hash(response->vp_octets + 2, /* peer challenge */
			       challenge->vp_octets, /* our challenge */
			       username_string,	/* user name */
			       mschapv1_challenge); /* resulting challenge */

		RDEBUG2("Client is using MS-CHAPv2 for %s, we need NT-Password",
		       username_string);

#ifdef __APPLE__
		if (inst->open_directory) {
			return do_od_mschap(request, response, challenge, username_string);
		}
#endif

		if (do_mschap(inst, request, nt_password, mschapv1_challenge,
			      response->vp_octets + 26, nthashhash,
			      do_ntlm_auth) < 0) {
			int i;
			char buffer[128];

			RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");

		do_error:
			snprintf(buffer, sizeof(buffer), "E=691 R=%d",
				 inst->allow_retry);

			if (inst->retry_msg) {
				snprintf(buffer + 9, sizeof(buffer) - 9, " C=");
				for (i = 0; i < 16; i++) {
					snprintf(buffer + 12 + i*2,
						 sizeof(buffer) - 12 - i*2, "%02x",
						 fr_rand() & 0xff);
				}
				snprintf(buffer + 44, sizeof(buffer) - 44,
					 " V=3 M=%s", inst->retry_msg);
			}
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets, "MS-CHAP-Error",
					 buffer, strlen(buffer));
			return RLM_MODULE_REJECT;
		}

		mschap_auth_response(username_string, /* without the domain */
			      nthashhash, /* nt-hash-hash */
			      response->vp_octets + 26, /* peer response */
			      response->vp_octets + 2, /* peer challenge */
			      challenge->vp_octets, /* our challenge */
			      msch2resp); /* calculated MPPE key */
		mschap_add_reply(request, &request->reply->vps, *response->vp_octets,
				 "MS-CHAP2-Success", msch2resp, 42);
		chap = 2;

	} else {		/* Neither CHAPv1 or CHAPv2 response: die */
		RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
		return RLM_MODULE_INVALID;
	}

	/*
	 *	We have a CHAP response, but the account may be
	 *	disabled.  Reject the user with the same error code
	 *	we use when their password is invalid.
	 */
	if (smb_ctrl) {
		/*
		 *	Account is disabled.
		 *
		 *	They're found, but they don't exist, so we
		 *	return 'not found'.
		 */
		if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
		    ((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0)) {
			RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal or workstatin trust account.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_NOTFOUND;
		}

		/*
		 *	User is locked out.
		 */
		if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
			RDEBUG2("SMB-Account-Ctrl says that the account is locked out.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=647 R=0", 9);
			return RLM_MODULE_USERLOCK;
		}
	}

	/* now create MPPE attributes */
	if (inst->use_mppe) {
		uint8_t mppe_sendkey[34];
		uint8_t mppe_recvkey[34];

		if (chap == 1){
			RDEBUG2("adding MS-CHAPv1 MPPE keys");
			memset(mppe_sendkey, 0, 32);
			if (lm_password) {
				memcpy(mppe_sendkey, lm_password->vp_octets, 8);
			}

			/*
			 *	According to RFC 2548 we
			 *	should send NT hash.  But in
			 *	practice it doesn't work.
			 *	Instead, we should send nthashhash
			 *
			 *	This is an error on RFC 2548.
			 */
			/*
			 *	do_mschap cares to zero nthashhash if NT hash
			 *	is not available.
			 */
			memcpy(mppe_sendkey + 8,
			       nthashhash, 16);
			mppe_add_reply(request,
				       "MS-CHAP-MPPE-Keys",
				       mppe_sendkey, 32);
		} else if (chap == 2) {
			RDEBUG2("adding MS-CHAPv2 MPPE keys");
			mppe_chap2_gen_keys128(nthashhash,
					       response->vp_octets + 26,
					       mppe_sendkey, mppe_recvkey);

			mppe_add_reply(request,
				       "MS-MPPE-Recv-Key",
				       mppe_recvkey, 16);
			mppe_add_reply(request,
				       "MS-MPPE-Send-Key",
				       mppe_sendkey, 16);

		}
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Policy",
				(inst->require_encryption)? "0x00000002":"0x00000001",
				T_OP_EQ);
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Types",
				(inst->require_strong)? "0x00000004":"0x00000006",
				T_OP_EQ);
	} /* else we weren't asked to use MPPE */

	return RLM_MODULE_OK;
#undef inst
}
示例#6
0
文件: pdbedit.c 项目: OPSF/uClinux
static int set_user_info (struct pdb_methods *in, const char *username, 
			  const char *fullname, const char *homedir, 
			  const char *acct_desc, 
			  const char *drive, const char *script, 
			  const char *profile, const char *account_control,
			  const char *user_sid, const char *user_domain,
			  const BOOL badpw, const BOOL hours)
{
	BOOL updated_autolock = False, updated_badpw = False;
	struct samu *sam_pwent=NULL;
	BOOL ret;
	
	if ( (sam_pwent = samu_new( NULL )) == NULL ) {
		return 1;
	}
	
	ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
	if (ret==False) {
		fprintf (stderr, "Username not found!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (hours) {
		uint8 hours_array[MAX_HOURS_LEN];
		uint32 hours_len;
		
		hours_len = pdb_get_hours_len(sam_pwent);
		memset(hours_array, 0xff, hours_len);
		
		pdb_set_hours(sam_pwent, hours_array, PDB_CHANGED);
	}

	if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
		DEBUG(2,("pdb_update_autolock_flag failed.\n"));
	}

	if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
		DEBUG(2,("pdb_update_bad_password_count failed.\n"));
	}

	if (fullname)
		pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
	if (acct_desc)
		pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
	if (homedir)
		pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
	if (drive)
		pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
	if (script)
		pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
	if (profile)
		pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
	if (user_domain)
		pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);

	if (account_control) {
		uint32 not_settable = ~(ACB_DISABLED|ACB_HOMDIRREQ|ACB_PWNOTREQ|
					ACB_PWNOEXP|ACB_AUTOLOCK);

		uint32 newflag = pdb_decode_acct_ctrl(account_control);

		if (newflag & not_settable) {
			fprintf(stderr, "Can only set [NDHLX] flags\n");
			TALLOC_FREE(sam_pwent);
			return -1;
		}

		pdb_set_acct_ctrl(sam_pwent,
				  (pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
				  PDB_CHANGED);
	}
	if (user_sid) {
		DOM_SID u_sid;
		if (!string_to_sid(&u_sid, user_sid)) {
			/* not a complete sid, may be a RID, try building a SID */
			int u_rid;
			
			if (sscanf(user_sid, "%d", &u_rid) != 1) {
				fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
				return -1;
			}
			sid_copy(&u_sid, get_global_sam_sid());
			sid_append_rid(&u_sid, u_rid);
		}
		pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
	}

	if (badpw) {
		pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
	}

	if (NT_STATUS_IS_OK(in->update_sam_account (in, sam_pwent)))
		print_user_info (in, username, True, False);
	else {
		fprintf (stderr, "Unable to modify entry!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}
	TALLOC_FREE(sam_pwent);
	return 0;
}