View | Details | Raw Unified | Return to bug 14 | Differences between
and this patch

Collapse All | Expand All

(-)TODO (-2 lines)
Lines 15-22 Link Here
15
15
16
- Replacement for setproctitle() - HP-UX support only currently
16
- Replacement for setproctitle() - HP-UX support only currently
17
17
18
- Handle changing passwords for the non-PAM expired password case
19
20
- Improve PAM support (a pam_lastlog module will cause sshd to exit)
18
- Improve PAM support (a pam_lastlog module will cause sshd to exit)
21
  and maybe support alternate forms of authentications like OPIE via
19
  and maybe support alternate forms of authentications like OPIE via
22
  pam?
20
  pam?
(-)acconfig.h (+3 lines)
Lines 25-30 Link Here
25
/* from environment and PATH */
25
/* from environment and PATH */
26
#undef LOGIN_PROGRAM_FALLBACK
26
#undef LOGIN_PROGRAM_FALLBACK
27
27
28
/* Path to passwd program */
29
#undef PASSWD_PROGRAM_PATH
30
28
/* Define if your password has a pw_class field */
31
/* Define if your password has a pw_class field */
29
#undef HAVE_PW_CLASS_IN_PASSWD
32
#undef HAVE_PW_CLASS_IN_PASSWD
30
33
(-)auth-pam.c (-7 / +2 lines)
Lines 60-66 Link Here
60
/* states for do_pam_conversation() */
60
/* states for do_pam_conversation() */
61
enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
61
enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
62
/* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */
62
/* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */
63
static int password_change_required = 0;
63
extern int password_change_required;
64
/* remember whether the last pam_authenticate() succeeded or not */
64
/* remember whether the last pam_authenticate() succeeded or not */
65
static int was_authenticated = 0;
65
static int was_authenticated = 0;
66
66
Lines 260-271 Link Here
260
		case PAM_NEW_AUTHTOK_REQD:
260
		case PAM_NEW_AUTHTOK_REQD:
261
			message_cat(&__pam_msg, use_privsep ?
261
			message_cat(&__pam_msg, use_privsep ?
262
			    NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
262
			    NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
263
			/* flag that password change is necessary */
263
			flag_password_change_required();
264
			password_change_required = 1;
265
			/* disallow other functionality for now */
266
			no_port_forwarding_flag |= 2;
267
			no_agent_forwarding_flag |= 2;
268
			no_x11_forwarding_flag |= 2;
269
			break;
264
			break;
270
#endif
265
#endif
271
		default:
266
		default:
(-)auth-passwd.c (-7 / +130 lines)
Lines 42-47 Link Here
42
#include "log.h"
42
#include "log.h"
43
#include "servconf.h"
43
#include "servconf.h"
44
#include "auth.h"
44
#include "auth.h"
45
#include "buffer.h"
46
#include "misc.h"
47
#include "channels.h"
48
#include "monitor_wrap.h"
49
#include "auth-options.h"
45
50
46
#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
51
#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
47
/* Don't need any of these headers for the PAM or SIA cases */
52
/* Don't need any of these headers for the PAM or SIA cases */
Lines 81-89 Link Here
81
#endif /* !USE_PAM && !HAVE_OSF_SIA */
86
#endif /* !USE_PAM && !HAVE_OSF_SIA */
82
87
83
extern ServerOptions options;
88
extern ServerOptions options;
84
#ifdef WITH_AIXAUTHENTICATE
89
extern Buffer login_message;
85
extern char *aixloginmsg;
90
extern int password_change_required;
86
#endif
91
pid_t password_change_pid;	/* pid used to reset forwarding flags */
87
92
88
/*
93
/*
89
 * Tries to authenticate the user using password.  Returns true if
94
 * Tries to authenticate the user using password.  Returns true if
Lines 123-128 Link Here
123
	/* deny if no user. */
128
	/* deny if no user. */
124
	if (pw == NULL)
129
	if (pw == NULL)
125
		return 0;
130
		return 0;
131
	buffer_init(&login_message);
126
#ifndef HAVE_CYGWIN
132
#ifndef HAVE_CYGWIN
127
       if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
133
       if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
128
		return 0;
134
		return 0;
Lines 149-161 Link Here
149
#endif
155
#endif
150
#ifdef WITH_AIXAUTHENTICATE
156
#ifdef WITH_AIXAUTHENTICATE
151
	authsuccess = (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0);
157
	authsuccess = (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0);
158
	aix_remove_embedded_newlines(authmsg);
152
159
153
	if (authsuccess)
160
	if (authsuccess) {
161
		char *msg;
162
163
		debug("authenticate() succeeded for user %s: %.100s",
164
		    pw->pw_name, authmsg);
154
	        /* We don't have a pty yet, so just label the line as "ssh" */
165
	        /* We don't have a pty yet, so just label the line as "ssh" */
155
	        if (loginsuccess(authctxt->user,
166
	        if (loginsuccess(authctxt->user,
156
			get_canonical_hostname(options.verify_reverse_mapping),
167
		    get_canonical_hostname(options.verify_reverse_mapping),
157
			"ssh", &aixloginmsg) < 0)
168
		    "ssh", &msg) < 0)
158
				aixloginmsg = NULL;
169
			msg = NULL;
170
		buffer_append(&login_message, msg, strlen(msg));
171
	} else {
172
		debug("AIX authenticate() failed for user %s: %.100s",
173
		    pw->pw_name, authmsg);
174
	}
175
	if (authmsg)
176
		xfree(authmsg);
159
177
160
	return(authsuccess);
178
	return(authsuccess);
161
#endif
179
#endif
Lines 232-235 Link Here
232
	/* Authentication is accepted if the encrypted passwords are identical. */
250
	/* Authentication is accepted if the encrypted passwords are identical. */
233
	return (strcmp(encrypted_password, pw_password) == 0);
251
	return (strcmp(encrypted_password, pw_password) == 0);
234
#endif /* !USE_PAM && !HAVE_OSF_SIA */
252
#endif /* !USE_PAM && !HAVE_OSF_SIA */
253
}
254
255
/*
256
 * Perform generic password change via tty. Like do_pam_chauthtok(),
257
 * it throws a fatal error if the password can't be changed.
258
 */
259
int
260
do_tty_change_password(struct passwd *pw)
261
{
262
	pid_t pid;
263
	int status;
264
	mysig_t old_signal;
265
266
	old_signal = mysignal(SIGCHLD, SIG_DFL);
267
268
	if ((pid = fork()) == -1)
269
		fatal("Couldn't fork: %s", strerror(errno));
270
271
	if (pid == 0) {
272
		setuid(pw->pw_uid);
273
		if (geteuid() == 0) 
274
			execl(PASSWD_PROGRAM_PATH, "passwd", pw->pw_name,
275
			    (char *)NULL);
276
		else
277
			execl(PASSWD_PROGRAM_PATH, "passwd", (char *)NULL);
278
			
279
		/* execl shouldn't return */
280
		fatal("Couldn't exec %s", PASSWD_PROGRAM_PATH);
281
		exit(1);
282
	}
283
284
	if (waitpid(pid, &status, 0) == -1)
285
		fatal("Couldn't wait for child: %s", strerror(errno));
286
	mysignal(SIGCHLD, old_signal);
287
288
	/*
289
	 * passwd sometimes returns 0 when the password has not been changed
290
	 * so we re-test via getpwnamallow
291
	 */
292
	if (WIFEXITED(status) && (WEXITSTATUS(status) == 0) &&
293
	    PRIVSEP(getpwnamallow(pw->pw_name)) != NULL) {
294
		debug("password changed sucessfully");
295
		flag_password_change_successful();
296
		return 1;
297
	} else {
298
		fatal("Failed to change password for %s, passwd returned %d",
299
		    pw->pw_name, status);
300
		return 0;
301
	}
302
}
303
304
/*
305
 * Because an expired password is changed after forking to exec the user's
306
 * shell, restoring the port forwarding flags is done by sending a
307
 * USR1 signal to the parent after the password is changed successfully.
308
 */
309
void
310
flag_password_change_required(void)
311
{
312
	debug("%s disabling forwarding flags", __func__);
313
	/* flag that password change is necessary */
314
	password_change_required = 1;
315
316
	/* disallow other functionality for now */
317
	no_port_forwarding_flag |= 2;
318
	no_agent_forwarding_flag |= 2;
319
	no_x11_forwarding_flag |= 2;
320
321
	/* set handler to reset flags */
322
	password_change_pid = getpid();
323
	mysignal(SIGUSR1, password_change_successful_handler);
324
}
325
326
/*
327
 * password change successful, tell parent to restore port
328
 * forwarding flags
329
 */
330
void
331
flag_password_change_successful(void)
332
{
333
	debug("%s signalling parent to reset forwarding flags", __func__);
334
	kill(password_change_pid, SIGUSR1);
335
336
	/* reset flags in local process too */
337
	password_change_required = 0;
338
	no_port_forwarding_flag &= ~2;
339
	no_agent_forwarding_flag &= ~2;
340
	no_x11_forwarding_flag &= ~2;
341
}
342
343
/*
344
 * signal handler to reset change flags
345
 */
346
void
347
password_change_successful_handler(int sig)
348
{
349
	debug("%s restoring port forwarding flags", __func__);
350
	mysignal(SIGUSR1, SIG_DFL);     /* unset handler */
351
352
	password_change_required = 0;
353
	no_port_forwarding_flag &= ~2;
354
	no_agent_forwarding_flag &= ~2;
355
	no_x11_forwarding_flag &= ~2;
356
	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
357
		channel_permit_all_opens();
235
}
358
}
(-)auth.c (-25 / +76 lines)
Lines 58-63 Link Here
58
/* Debugging messages */
58
/* Debugging messages */
59
Buffer auth_debug;
59
Buffer auth_debug;
60
int auth_debug_init;
60
int auth_debug_init;
61
extern int password_change_required;
62
extern Buffer expire_message;
61
63
62
/*
64
/*
63
 * Check if the user is allowed to log in via ssh. If user is listed
65
 * Check if the user is allowed to log in via ssh. If user is listed
Lines 75-87 Link Here
75
	const char *hostname = NULL, *ipaddr = NULL, *passwd;
77
	const char *hostname = NULL, *ipaddr = NULL, *passwd;
76
	char *shell;
78
	char *shell;
77
	int i;
79
	int i;
78
#ifdef WITH_AIXAUTHENTICATE
79
	char *loginmsg;
80
#endif /* WITH_AIXAUTHENTICATE */
81
#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
80
#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
82
	struct spwd *spw;
81
	struct spwd *spw;
83
#if !defined(USE_PAM) && defined(HAS_SHADOW_EXPIRE)
82
#if !defined(USE_PAM) && defined(HAS_SHADOW_EXPIRE)
84
	time_t today;
83
	time_t today, expiredate;
85
#endif
84
#endif
86
#endif
85
#endif
87
86
Lines 121-139 Link Here
121
	if (spw->sp_expire != -1 && today > spw->sp_expire) {
120
	if (spw->sp_expire != -1 && today > spw->sp_expire) {
122
		log("Account %.100s has expired", pw->pw_name);
121
		log("Account %.100s has expired", pw->pw_name);
123
		return 0;
122
		return 0;
123
	} else if (spw->sp_expire != -1 &&
124
	    spw->sp_expire - today < spw->sp_warn) {
125
		char msg[100];
126
127
		snprintf(msg, 100,
128
		    "Your account will expire in %d days.\n",
129
		    (int)(spw->sp_expire - today));
130
		buffer_append(&expire_message, msg, strlen(msg));
124
	}
131
	}
125
132
126
	if (spw->sp_lstchg == 0) {
133
	if (spw->sp_lstchg == 0) {
127
		log("User %.100s password has expired (root forced)",
134
		log("User %.100s password has expired (root forced)",
128
		    pw->pw_name);
135
		    pw->pw_name);
129
		return 0;
136
		password_change_required = 1;
137
		buffer_append(&expire_message,
138
		    "You must change your password now.\n", 35); 
130
	}
139
	}
131
140
132
	if (spw->sp_max != -1 &&
141
	expiredate = spw->sp_lstchg + spw->sp_max;
133
	    today > spw->sp_lstchg + spw->sp_max) {
142
	if (spw->sp_max != -1 && today > expiredate) {
134
		log("User %.100s password has expired (password aged)",
143
		log("User %.100s password has expired (password aged)",
135
		    pw->pw_name);
144
		    pw->pw_name);
136
		return 0;
145
		password_change_required = 1;
146
		buffer_append(&expire_message,
147
		    "Your password has expired, you must change it now.\n",
148
		    51);
149
	} else if (spw->sp_max != -1 && expiredate - today < spw->sp_warn) {
150
		char msg[100];
151
152
		snprintf(msg, 100,
153
		    "Your password will expire in %d days.\n",
154
		    (int)(expiredate - today));
155
		buffer_append(&expire_message, msg, strlen(msg));
137
	}
156
	}
138
#endif
157
#endif
139
158
Lines 222-248 Link Here
222
	 * PermitRootLogin to control logins via ssh), or if running as
241
	 * PermitRootLogin to control logins via ssh), or if running as
223
	 * non-root user (since loginrestrictions will always fail).
242
	 * non-root user (since loginrestrictions will always fail).
224
	 */
243
	 */
225
	if ( (pw->pw_uid != 0) && (geteuid() == 0) &&
244
	if ( (pw->pw_uid != 0) && (geteuid() == 0) ) {
226
	    loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &loginmsg) != 0) {
227
		int loginrestrict_errno = errno;
245
		int loginrestrict_errno = errno;
246
		char *msg;
228
247
229
		if (loginmsg && *loginmsg) {
248
		/* check for AIX account restrictions */
230
			/* Remove embedded newlines (if any) */
249
		if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg) != 0) {
231
			char *p;
250
			if (msg && *msg) {
232
			for (p = loginmsg; *p; p++) {
251
				aix_remove_embedded_newlines(msg);
233
				if (*p == '\n')
252
				log("Login restricted for %s: %.100s",
234
					*p = ' ';
253
				    pw->pw_name, msg);
254
				xfree(msg);
235
			}
255
			}
236
			/* Remove trailing newline */
256
237
			*--p = '\0';
257
			/* Don't fail if /etc/nologin  set */
238
			log("Login restricted for %s: %.100s", pw->pw_name, 
258
	   	 	if (!(loginrestrict_errno == EPERM && 
239
			    loginmsg);
259
			    stat(_PATH_NOLOGIN, &st) == 0))
240
		}
260
				return 0;
241
		/* Don't fail if /etc/nologin  set */
261
		}
242
	    	if (!(loginrestrict_errno == EPERM && 
243
		    stat(_PATH_NOLOGIN, &st) == 0))
244
			return 0;
245
	}
262
	}
263
264
	/*
265
	 * Check AIX password expiry.  Only check when running as root.
266
	 * Unpriv'ed users can't access /etc/security/passwd or
267
	 * /etc/security/user so passwdexpired will always fail.
268
	 */
269
	if (geteuid() == 0) {
270
		char *msg;
271
		int passexpcode;
272
273
		passexpcode = passwdexpired(pw->pw_name, &msg);
274
		buffer_append(&expire_message, msg, strlen(msg));
275
		if (msg && *msg)
276
			aix_remove_embedded_newlines(msg);
277
		debug("AIX passwdexpired returned %d, msg %.100s",
278
		    passexpcode, msg);
279
280
		switch (passexpcode) {
281
			case 0:	/* success, password not expired */
282
				break;
283
			case 1:	/* expired, password change required */
284
				flag_password_change_required();
285
				break;
286
			default: /* only admin can change (2) or other error (-1) */
287
				log("Password can't be changed for user %s: %.100s",
288
				    pw->pw_name, msg);
289
				if (msg)
290
					xfree(msg);
291
				return 0;
292
  		}
293
		if (msg)
294
			xfree(msg);
295
  	}
246
#endif /* WITH_AIXAUTHENTICATE */
296
#endif /* WITH_AIXAUTHENTICATE */
247
297
248
	/* We found no reason not to let this user try to log on... */
298
	/* We found no reason not to let this user try to log on... */
Lines 508-513 Link Here
508
#endif
558
#endif
509
	struct passwd *pw;
559
	struct passwd *pw;
510
560
561
	buffer_init(&expire_message);
511
	pw = getpwnam(user);
562
	pw = getpwnam(user);
512
	if (pw == NULL) {
563
	if (pw == NULL) {
513
		log("Illegal user %.100s from %.100s",
564
		log("Illegal user %.100s from %.100s",
(-)auth.h (+3 lines)
Lines 101-106 Link Here
101
101
102
int	 auth_rhosts_rsa(struct passwd *, char *, Key *);
102
int	 auth_rhosts_rsa(struct passwd *, char *, Key *);
103
int      auth_password(Authctxt *, const char *);
103
int      auth_password(Authctxt *, const char *);
104
int	 do_tty_change_password(struct passwd *pw);
104
int      auth_rsa(struct passwd *, BIGNUM *);
105
int      auth_rsa(struct passwd *, BIGNUM *);
105
int      auth_rsa_challenge_dialog(Key *);
106
int      auth_rsa_challenge_dialog(Key *);
106
BIGNUM	*auth_rsa_generate_challenge(Key *);
107
BIGNUM	*auth_rsa_generate_challenge(Key *);
Lines 183-188 Link Here
183
void	 auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
184
void	 auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
184
void	 auth_debug_send(void);
185
void	 auth_debug_send(void);
185
void	 auth_debug_reset(void);
186
void	 auth_debug_reset(void);
187
188
void	password_change_successful_handler(int);
186
189
187
#define AUTH_FAIL_MAX 6
190
#define AUTH_FAIL_MAX 6
188
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
191
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
(-)configure.ac (+7 lines)
Lines 41-46 Link Here
41
	fi
41
	fi
42
fi
42
fi
43
43
44
AC_PATH_PROG(PASSWD_PROGRAM_PATH, passwd)
45
if test ! -z "$PASSWD_PROGRAM_PATH" ; then
46
	AC_DEFINE_UNQUOTED(PASSWD_PROGRAM_PATH, "$PASSWD_PROGRAM_PATH")
47
else
48
	AC_MSG_ERROR([*** passwd command not found - check config.log ***])
49
fi
50
44
if test -z "$LD" ; then
51
if test -z "$LD" ; then
45
	LD=$CC
52
	LD=$CC
46
fi
53
fi
(-)session.c (-12 / +22 lines)
Lines 102-111 Link Here
102
/* data */
102
/* data */
103
#define MAX_SESSIONS 10
103
#define MAX_SESSIONS 10
104
Session	sessions[MAX_SESSIONS];
104
Session	sessions[MAX_SESSIONS];
105
105
Buffer expire_message;	/* "password will expire/has expired" messages */
106
#ifdef WITH_AIXAUTHENTICATE
106
Buffer login_message;	/* message to be displayed after login */
107
char *aixloginmsg;
107
int password_change_required = 0;
108
#endif /* WITH_AIXAUTHENTICATE */
109
108
110
#ifdef HAVE_LOGIN_CAP
109
#ifdef HAVE_LOGIN_CAP
111
login_cap_t *lc;
110
login_cap_t *lc;
Lines 456-465 Link Here
456
#if defined(USE_PAM)
455
#if defined(USE_PAM)
457
	do_pam_session(s->pw->pw_name, NULL);
456
	do_pam_session(s->pw->pw_name, NULL);
458
	do_pam_setcred(1);
457
	do_pam_setcred(1);
459
	if (is_pam_password_change_required())
458
#endif /* USE_PAM */
459
460
	if (password_change_required)
460
		packet_disconnect("Password change required but no "
461
		packet_disconnect("Password change required but no "
461
		    "TTY available");
462
		    "TTY available");
462
#endif /* USE_PAM */
463
463
464
	/* Fork the child. */
464
	/* Fork the child. */
465
	if ((pid = fork()) == 0) {
465
	if ((pid = fork()) == 0) {
Lines 723-728 Link Here
723
	socklen_t fromlen;
723
	socklen_t fromlen;
724
	struct sockaddr_storage from;
724
	struct sockaddr_storage from;
725
	struct passwd * pw = s->pw;
725
	struct passwd * pw = s->pw;
726
	int password_changed = 0;
726
	pid_t pid = getpid();
727
	pid_t pid = getpid();
727
728
728
	/*
729
	/*
Lines 746-761 Link Here
746
		    options.verify_reverse_mapping),
747
		    options.verify_reverse_mapping),
747
		    (struct sockaddr *)&from, fromlen);
748
		    (struct sockaddr *)&from, fromlen);
748
749
749
#ifdef USE_PAM
750
	/*
750
	/*
751
	 * If password change is needed, do it now.
751
	 * If password change is needed, do it now.
752
	 * This needs to occur before the ~/.hushlogin check.
752
	 * This needs to occur before the ~/.hushlogin check.
753
	 */
753
	 */
754
#ifdef USE_PAM
754
	if (is_pam_password_change_required()) {
755
	if (is_pam_password_change_required()) {
755
		print_pam_messages();
756
		print_pam_messages();
756
		do_pam_chauthtok();
757
		if (!use_privsep)
758
			do_pam_chauthtok();
757
	}
759
	}
758
#endif
760
#endif
761
	buffer_append(&expire_message, "\0", 1);
762
	if (password_change_required) {
763
		puts((char *)buffer_ptr(&expire_message));
764
		do_tty_change_password(pw);
765
		password_changed = 1;
766
	}
759
767
760
	if (check_quietlogin(s, command))
768
	if (check_quietlogin(s, command))
761
		return;
769
		return;
Lines 764-773 Link Here
764
	if (!is_pam_password_change_required())
772
	if (!is_pam_password_change_required())
765
		print_pam_messages();
773
		print_pam_messages();
766
#endif /* USE_PAM */
774
#endif /* USE_PAM */
767
#ifdef WITH_AIXAUTHENTICATE
775
	if (!password_changed)
768
	if (aixloginmsg && *aixloginmsg)
776
		printf("%s", (char *)buffer_ptr(&expire_message));
769
		printf("%s\n", aixloginmsg);
777
770
#endif /* WITH_AIXAUTHENTICATE */
778
	/* display post-login message */
779
	buffer_append(&login_message, "\0", 1);
780
	puts((char *)buffer_ptr(&login_message));
771
781
772
#ifndef NO_SSH_LASTLOG
782
#ifndef NO_SSH_LASTLOG
773
	if (options.print_lastlog && s->last_login_time != 0) {
783
	if (options.print_lastlog && s->last_login_time != 0) {
(-)openbsd-compat/port-aix.c (-1 / +21 lines)
Lines 52-56 Link Here
52
	xfree(cp);
52
	xfree(cp);
53
}
53
}
54
54
55
#endif /* _AIX */
55
#ifdef WITH_AIXAUTHENTICATE
56
/*
57
 * Remove embedded newlines in string (if any).
58
 * Used before logging messages returned by AIX authentication functions
59
 * so the message is logged on one line.
60
 */
61
void
62
aix_remove_embedded_newlines(char *p)
63
{
64
	if (p == NULL)
65
		return;
66
67
	for (; *p; p++) {
68
		if (*p == '\n')
69
			*p = ' ';
70
	}
71
	/* Remove trailing newline */
72
	*--p = '\0';
73
}
74
#endif /* WITH_AIXAUTHENTICATE */
56
75
76
#endif /* _AIX */
(-)openbsd-compat/port-aix.h (+1 lines)
Lines 26-29 Link Here
26
26
27
#ifdef _AIX
27
#ifdef _AIX
28
void aix_usrinfo(struct passwd *pw);
28
void aix_usrinfo(struct passwd *pw);
29
void aix_remove_embedded_newlines(char *);
29
#endif /* _AIX */
30
#endif /* _AIX */

Return to bug 14