Skip to content

Commit cfe7560

Browse files
committed
add SRP user authentication method
Implement the SRP (Secure Remote Password) UAM for AFP, as used by Apple Time Capsule. The protocol uses SRP-6a with SHA-1, MGF1 KDF, and RFC 5054 group #2 (1536-bit). afppasswd is modified to operate on SRP storage file by default, which stores per-user salts and verifiers. afppasswd retains the legacy RandNum functionality activated with the -r flag. afppasswd -a now takes username as argument rather than previous positional username arugment
1 parent 3031dbe commit cfe7560

13 files changed

Lines changed: 1452 additions & 125 deletions

File tree

bin/afppasswd/afppasswd.c

Lines changed: 481 additions & 65 deletions
Large diffs are not rendered by default.

bin/afppasswd/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ executable(
2121
link_with: afppasswd_libs,
2222
c_args: [
2323
afpdpwfile,
24+
afpdsrppwfile,
2425
dversion,
2526
],
2627
install: true,

doc/manpages/man1/afppasswd.1.md

Lines changed: 87 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,76 +4,130 @@ afppasswd — AFP password maintenance utility
44

55
# Synopsis
66

7-
**afppasswd** [-acfn] [-p *afppasswd file*] [-u *minimum uid*] [-w *password string*]
7+
**afppasswd** [-cfn] [-r] [-a *username*] [-p *path*] [-u *minimum uid*] [-w *password string*]
88

9-
# Description
10-
11-
**afppasswd** creates and maintains an *afppasswd* file, which supplies the
12-
user credentials for the "Randnum exchange" and "2-Way Randnum exchange"
13-
User Authentication Modules.
9+
**afppasswd** [-r]
1410

15-
**afppasswd** can either be called by root with parameters to manage all
16-
user credentials, or by local system users with no parameters to change
17-
their own AFP passwords.
11+
# Description
1812

19-
> ***NOTE:*** With this utility you can only change the passwords used by these two
20-
Random Number UAMs. As they provide only weak password encryption, their
21-
use is discouraged unless one has to support very old AFP clients that
22-
can not deal with the more secure "DHX" or "DHX2" UAMs.
13+
**afppasswd** creates and maintains the credential file used by the SRP
14+
("Secure Remote Password") UAM and, with **-r**, the legacy *afppasswd*
15+
file used by the "Randnum exchange" and "2-Way Randnum exchange" UAMs.
16+
17+
By default **afppasswd** operates in **SRP mode** and stores per-user
18+
salts and verifiers in the SRP verifier file (default *afppasswd.srp*
19+
under the netatalk configuration directory, or whatever is configured
20+
via the "**srp passwd file**" option in **afp.conf**(5)). Pass **-r**
21+
to operate on the legacy Randnum file (default *afppasswd* under the
22+
netatalk configuration directory, or as configured via the
23+
"**passwd file**" option) instead.
24+
25+
There are two invocation styles:
26+
27+
- **As root**, **afppasswd** manages credentials for any system user.
28+
The user is named with **-a** *username* (which both adds new entries
29+
and updates existing ones), or the entire file is initialised at once
30+
with **-c**.
31+
- **As a regular user**, **afppasswd** takes no positional arguments and
32+
changes the calling user's own AFP password: for SRP by default and with
33+
**-r** for the legacy RandNum UAM.
34+
35+
The named user must already exist as a local system user.
36+
37+
> ***NOTE:*** The legacy Randnum and 2-Way Randnum UAMs only provide
38+
weak password protection and are discouraged. They should only be enabled
39+
to support very old AFP clients that cannot use SRP, DHX, or DHX2.
40+
> If a file named `<passwd file>.key` exists, Randnum uses its hex-encoded
41+
> 8-byte DES key to encrypt the stored password; otherwise the password is
42+
> stored as raw hex in the legacy *afppasswd* file.
2343
2444
# Examples
2545

26-
Administrator initializing *afppasswd* file and adding a new user:
46+
Administrator initialising the SRP verifier file and adding a new user:
2747

2848
example% sudo afppasswd -c
2949
example% sudo afppasswd -a newuser
3050
Enter NEW AFP password: (hidden)
3151
Enter NEW AFP password again: (hidden)
32-
afppasswd: updated password.
52+
afppasswd: updated SRP verifier.
53+
54+
Administrator updating an existing user's SRP password:
3355

34-
Note that newuser must already exist as a local system user.
56+
example% sudo afppasswd -a someuser
3557

36-
Local user changing their own password:
58+
Local user changing their own SRP password:
3759

3860
example% afppasswd
39-
Enter NEW AFP password: (hidden)
40-
Enter NEW AFP password again: (hidden)
41-
afppasswd: updated password.
61+
62+
Administrator managing the legacy Randnum file at a non-default path:
63+
64+
example% sudo afppasswd -r -c -p /usr/local/etc/afppasswd
65+
example% sudo afppasswd -r -a olduser -p /usr/local/etc/afppasswd
4266

4367
# Options
4468

45-
**-a**
69+
**-a** *username*
4670

47-
> Add a new user to the *afppasswd* file.
71+
> Add or update the named user. Required when an administrator operates
72+
> on a specific user. Non-root invocations always operate on the calling
73+
> user and do not accept this option.
4874
4975
**-c**
5076

51-
> Create and/or initialize *afppasswd* file or specific user.
77+
> Create and initialise the password/verifier file. Existing entries are
78+
> populated as placeholders for every local system user with a uid at or
79+
> above the **-u** threshold; passwords still need to be set individually
80+
> with **-a**.
5281
5382
**-f**
5483

55-
> Force the current action.
84+
> Force the action. With **-c**, allows overwriting an existing
85+
> password/verifier file.
86+
87+
**-r**
88+
89+
> Operate on the legacy Randnum *afppasswd* file instead of the SRP
90+
> verifier file. Affects which file is read or created and which default
91+
> path is used when **-p** is not given.
5692
5793
**-p** *path*
5894

59-
> Path to *afppasswd* file.
95+
> Override the default path of the password/verifier file. The default is
96+
> the SRP verifier file in SRP mode and the Randnum *afppasswd* file with
97+
> **-r**; both defaults can also be configured globally in **afp.conf**(5)
98+
> via "**srp passwd file**" and "**passwd file**" respectively.
6099
61100
**-n**
62101

63-
> If cracklib support is built into *netatalk* this option will cause
64-
cracklib checking to be disabled, if the superuser does not want to have
65-
the password run against the cracklib dictionary.
102+
> If cracklib support is built into *netatalk*, this option disables
103+
> cracklib checking, in case the superuser does not want to run the
104+
> password against the cracklib dictionary.
66105
67106
**-u** *minimum uid*
68107

69-
> This is the minimum *user id* (uid) that **afppasswd** will use when
70-
creating users.
108+
> The minimum *user id* (uid) that **afppasswd** considers when **-c**
109+
> walks the local user database to populate the file. Defaults to 100.
71110
72111
**-w** *password string*
73112

74-
> Use string as password, instead of typing it interactively. Please use
75-
this option only if absolutely necessary, since the password may remain
76-
in the terminal history in plain text.
113+
> Use *string* as the password instead of typing it interactively. Use
114+
> this option only when absolutely necessary, since the password may
115+
> remain in the terminal history in plain text.
116+
117+
# Files
118+
119+
*afppasswd.srp*
120+
121+
> Default SRP verifier file, located under the netatalk configuration
122+
> directory. One line per user, formatted as
123+
> *username:hex_salt:hex_verifier*. Override with **-p** or with the
124+
> "**srp passwd file**" option in **afp.conf**(5).
125+
126+
*afppasswd*
127+
128+
> Default legacy Randnum file, located under the netatalk configuration
129+
> directory. Used only with **-r**. Override with **-p** or with the
130+
> "**passwd file**" option in **afp.conf**(5).
77131
78132
# See Also
79133

doc/manpages/man5/afp.conf.5.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -239,16 +239,6 @@ nt domain = *domain* **(G)**; nt separator = *SEPARATOR* **(G)**
239239
username from login and then tries to authenticate with the result
240240
through the available and active UAM authentication modules.
241241
242-
save password = *BOOLEAN* (default: *yes*) **(G)**
243-
244-
> Enables or disables the ability of clients to save passwords locally.
245-
Setting this option to *no* will send this hint to clients, but it is up to the client to honor it.
246-
247-
set password = *BOOLEAN* (default: *no*) **(G)**
248-
249-
> Enables or disables the ability of clients to change their passwords.
250-
Setting this option to *yes* will allow clients to change their passwords if the UAM in use supports this feature.
251-
252242
uam list = *uam list* **(G)**
253243
254244
> Space or comma separated list of UAMs. (The default is "uams_dhx.so
@@ -271,7 +261,6 @@ in the clear. Compatible with Mac OS 9 and earlier.
271261
authentication (requires a separate file containing the passwords,
272262
either the default *afppasswd* file or the one specified via
273263
"**passwd file**"). See **afppasswd**(1) for details.
274-
Compatible with Mac OS 9 and earlier.
275264
>
276265
> uams_dhx.so
277266
>
@@ -285,7 +274,12 @@ Compatible with Mac OS 9 and earlier.
285274
>
286275
> uam_gss.so
287276
>
288-
> > Allow Kerberos V for authentication (optional)
277+
> > Allow Kerberos V for authentication
278+
>
279+
> uams_srp.so
280+
> > Allow SRP ("Secure Remote Password") for authentication. Requires a separate
281+
file containing the SRP salts and verifiers, either the default *afppasswd.srp* file
282+
or the one specified via "**srp passwd file**". See **afppasswd**(1) for details.
289283
290284
uam path = *path* **(G)**
291285
@@ -346,12 +340,26 @@ same as **unix charset**.
346340
347341
passwd file = *path* **(G)**
348342
349-
> Sets the path to the Randnum UAM *afppasswd* file for this server.
343+
> Sets the path to the Randnum UAM password file for this server.
350344
351345
passwd minlen = *number* **(G)**
352346
353347
> Sets the minimum password length, if supported by the UAM
354348
349+
save password = *BOOLEAN* (default: *yes*) **(G)**
350+
351+
> Enables or disables the ability of clients to save passwords locally.
352+
Setting this option to *no* will send this hint to clients, but it is up to the client to honor it.
353+
354+
set password = *BOOLEAN* (default: *no*) **(G)**
355+
356+
> Enables or disables the ability of clients to change their passwords.
357+
Setting this option to *yes* will allow clients to change their passwords if the UAM in use supports this feature.
358+
359+
srp passwd file = *path* **(G)**
360+
361+
> Sets the path to the SRP UAM verifier file for this server.
362+
355363
## Network Options
356364
357365
advertise ssh = *BOOLEAN* (default: *no*) **(G)**

doc/manual/Authentication.md

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ Netatalk supports the following UAMs by default:
2323

2424
- "DHCAST128" UAM (a.k.a. DHX; stronger password encryption)
2525

26-
- "DHX2" UAM (successor of DHCAST128)
26+
- "DHX2" UAM (successor of DHCAST128 with even stronger password encryption)
27+
28+
- "SRP" UAM ("Secure Remote Password", strongest password encryption, separate verifier storage)
2729

2830
With Kerberos support enabled at compile time, Netatalk also supports:
2931

@@ -68,16 +70,17 @@ DHX2 is sufficient and provides the strongest encryption.
6870

6971
- "Randnum exchange"/"2-Way Randnum exchange" uses only 56-bit DES for encryption,
7072
so it should also be avoided.
71-
An additional disadvantage is that passwords must be stored in cleartext on the server,
72-
and these UAMs do not integrate with PAM or classic */etc/shadow*.
73-
You must administer passwords separately using the **afppasswd** utility.
73+
An additional disadvantage is that passwords must be stored as raw hex on the server.
7474

7575
However, this is the strongest form of authentication available for
7676
Macintosh System Software 7.1 or earlier.
7777

7878
- "DHCAST128" ("DHX") or "DHX2" is the best choice for most users,
7979
combining stronger encryption with PAM integration.
8080

81+
- "SRP" is the strongest UAM, but it requires a separate file to store per-user salts and verifiers.
82+
If you don't mind the extra maintenance overhead of this file, SRP is the best choice for security-conscious users.
83+
8184
- The Kerberos V ("Client Krb v2")
8285
UAM enables true single sign-on scenarios using Kerberos tickets.
8386
The password is not sent over the network.
@@ -92,7 +95,21 @@ For a more detailed overview of the technical implications of the different UAMs
9295
see Apple's [File Server Security](http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/AFP/AFPSecurity/AFPSecurity.html#//apple_ref/doc/uid/TP40000854-CH232-SW1)
9396
documentation.
9497

95-
## Using different authentication sources with specific UAMs
98+
## Password storage
99+
100+
Randnum and SRP do not use system passwords directly. They both rely on
101+
separate files managed with **afppasswd**:
102+
103+
- **Randnum** uses the legacy *afppasswd* file. By default it stores the raw
104+
password as hex. If an optional key file exists alongside the Randnum
105+
password file (same path with a `.key` suffix), the stored password is
106+
DES-encrypted using that key instead. To use a key file, create
107+
`<passwd file>.key` containing 16 hex characters (8 bytes) and restrict
108+
permissions (for example, owner-readable only).
109+
110+
- **SRP** uses *afppasswd.srp*, which stores per-user salts and verifiers.
111+
112+
## Using different authentication backends
96113

97114
Some UAMs support different authentication backends,
98115
namely **uams_clrtxt.so**, **uams_dhx.so**, and **uams_dhx2.so**.
@@ -114,19 +131,18 @@ The main advantage of PAM is that it integrates Netatalk into centralized authen
114131
such as LDAP, NIS, and similar systems.
115132
Keep in mind that the security of your users' login credentials in such scenarios
116133
also depends on the encryption strength of the UAM in use.
117-
Consider eliminating weak UAMs like "ClearTxt Passwrd" and "Randnum exchange" entirely from your network.
118134

119135
## Netatalk UAM overview table
120136

121137
An overview of the officially supported UAMs on Macs.
122138

123-
| UAM | No User Auth | Cleartxt Passwrd | RandNum Exchange | DHCAST128 | DHX2 | Kerberos V |
124-
|------------------|---------------|------------------|------------------|--------------|---------------|------------------|
125-
| Password length | guest access | max 8 chars | max 8 chars | max 64 chars | max 256 chars | Kerberos tickets |
126-
| Client support | built-in into all Mac OS versions | built-in in all Mac OS versions except 10.0. Has to be activated explicitly in later Mac OS X versions | built-in into almost all Mac OS versions | built-in since AppleShare client 3.8.4, available as a plug-in for 3.8.3, integrated in macOS's AFP client | built-in since Mac OS X 10.2 | built-in since Mac OS X 10.2 |
127-
| Encryption | Enables guest access without authentication between client and server. | Password will be sent in cleartext over the wire. Just as bad as it sounds, therefore avoid at all if possible (note: providing NetBoot services requires the ClearTxt UAM) | 8-byte random numbers are sent over the wire, comparable with DES, 56 bits. Vulnerable to offline dictionary attack. Requires passwords in clear on the server. | Password will be encrypted with 128 bit CAST, user will be authenticated against the server but not vice versa. Therefore weak against man-in-the-middle attacks. | Password will be encrypted with 128 bit CAST in CBC mode. User will be authenticated against the server but not vice versa. Therefore weak against man-in-the-middle attacks. | Password is not sent over the network. Due to the service principal detection method, this authentication method is vulnerable to man-in-the-middle attacks. |
128-
| Server support | uams_guest.so | uams_clrtxt.so | uams_randnum.so | uams_dhx.so | uams_dhx2.so | uams_gss.so |
129-
| Password storage | None | Either system auth or PAM | Passwords stored in clear text in a separate text file | Either system auth or PAM | Either system auth or PAM | At the Kerberos Key Distribution Center |
139+
| UAM | No User Auth | Cleartxt Passwrd | RandNum Exchange | DHCAST128 | DHX2 | Kerberos V | SRP |
140+
| ---------------- | ------------- | ---------------- | ---------------- | ------------ | ------------- | ---------------- | ---------------- |
141+
| Password length | guest access | max 8 chars | max 8 chars | max 64 chars | max 256 chars | Kerberos tickets | max 256 chars |
142+
| Client support | built-in into all Mac OS versions | built-in in all Mac OS versions except 10.0. Has to be activated explicitly in later Mac OS X versions | built-in into almost all Mac OS versions | built-in since AppleShare client 3.8.4, available as a plug-in for 3.8.3, integrated in macOS's AFP client | built-in since Mac OS X 10.2 | built-in since Mac OS X 10.2 | built-in since Mac OS X 10.7 |
143+
| Encryption | Enables guest access without authentication between client and server. | Password will be sent in cleartext over the wire. Just as bad as it sounds, therefore avoid at all costs. | 8-byte random numbers are sent over the wire, comparable with DES, 56 bits. Vulnerable to offline dictionary attack. Requires passwords in clear on the server. | Password will be encrypted with 128 bit CAST, user will be authenticated against the server but not vice versa. Therefore weak against man-in-the-middle attacks. | Password will be encrypted with 128 bit CAST in CBC mode. User will be authenticated against the server but not vice versa. Therefore weak against man-in-the-middle attacks. | Password is not sent over the network. Due to the service principal detection method, this authentication method is vulnerable to man-in-the-middle attacks. | Password is never sent; SRP uses a verifier and mutual proofs (M1/M2) to authenticate both client and server, providing protection against man‑in‑the‑middle attacks. |
144+
| Server support | uams_guest.so | uams_clrtxt.so | uams_randnum.so | uams_dhx.so | uams_dhx2.so | uams_gss.so | uams_srp.so |
145+
| Password storage | None | Either system auth or PAM | Separate *afppasswd* file; raw hex or DES-encrypted with *.key* | Either system auth or PAM | Either system auth or PAM | At the Kerberos Key Distribution Center | In a separate *afppasswd.srp* verifier file |
130146

131147
Note that a number of open-source and other third-party AFP clients exist.
132148
Refer to their documentation for a list of supported UAMs.

etc/afpd/uam.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,11 @@ int uam_afpserver_option(void *private, const int what, void *option,
426426
*len = strlen(obj->options.passwdfile);
427427
break;
428428

429+
case UAM_PASSWD_SRP_FILENAME:
430+
*buf = obj->options.srppasswdfile;
431+
*len = strlen(obj->options.srppasswdfile);
432+
break;
433+
429434
case UAM_PASSWD_MINLENGTH:
430435
*((int *) option) = obj->options.passwdminlen;
431436
*len = sizeof(obj->options.passwdminlen);

etc/uams/meson.build

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ library(
7575
install_dir: libdir / 'netatalk',
7676
)
7777

78+
library(
79+
'uams_srp',
80+
['uams_srp.c'],
81+
include_directories: root_includes,
82+
dependencies: [libgcrypt],
83+
name_prefix: '',
84+
name_suffix: lib_suffix,
85+
override_options: 'b_lundef=false',
86+
install: true,
87+
install_dir: libdir / 'netatalk',
88+
)
89+
7890
if have_pam
7991
library(
8092
'uams_dhx_pam',

0 commit comments

Comments
 (0)