-
Notifications
You must be signed in to change notification settings - Fork 100
Dev Docs Components Auth
WIP - ALL LINKS IN THIS WIKI STRUCTURE ARE CURRENTLY BROKEN DURING WIKI MIGRATION
THESE ARE COMMUNITY DOCS
Netatalk's authentication system is built around User Authentication Modules (UAMs) that provide pluggable authentication mechanisms. This modular design allows support for various authentication methods while maintaining compatibility with different Mac client versions and organizational security requirements.
-
include/atalk/uam.h
- UAM interface definitions and structures -
etc/afpd/auth.c
- Main authentication handling and session management -
etc/afpd/uam.c
- UAM module loading and registration system -
etc/uams/
- Directory containing all UAM module implementations -
libatalk/util/
- Authentication utility functions and helpers
Netatalk's UAM (User Authentication Module) system implements a sophisticated pluggable architecture that allows dynamic loading of authentication methods. Each UAM is a dynamically loadable module that exports a standardized interface.
graph TB
subgraph "UAM Module Interface"
A[uam_export Structure]
B[uam_type: MODULE_SERVER/CLIENT]
C[uam_version: API Version]
D[uam_setup: Initialization Function]
E[uam_cleanup: Cleanup Function]
end
subgraph "Registration System"
F[uam_register Function]
G[uam_unregister Function]
H[UAM Option Flags]
I[Helper Functions]
end
subgraph "Authentication Types"
J[UAM_SERVER_LOGIN]
K[UAM_SERVER_CHANGEPW]
L[UAM_SERVER_PRINTAUTH]
M[UAM_SERVER_LOGIN_EXT]
end
subgraph "Session Management"
N[session_info Structure]
O[Session Key Management]
P[Token Management]
Q[Client ID Tracking]
end
A --> F
F --> J
F --> K
F --> L
F --> M
F --> H
N --> O
N --> P
N --> Q
Core UAM System Files:
-
include/atalk/uam.h
- UAM export structures and registration functions -
etc/afpd/uam.c
- Dynamic module loading and UAM management -
etc/afpd/auth.c
- Authentication flow coordination -
libatalk/util/
- Authentication utilities and session handling
// Core UAM module export structure (include/atalk/uam.h)
struct uam_export {
int uam_type; // UAM_MODULE_SERVER or UAM_MODULE_CLIENT
int uam_version; // UAM_MODULE_VERSION (currently 1)
int (*uam_setup)(void *, const char *); // Module initialization
void (*uam_cleanup)(void); // Module cleanup
};
// Dynamic module loading architecture
// Each UAM module must export:
// 1. uam_attach() function that returns uam_export structure
// 2. Implement required authentication callbacks
// 3. Support UAM option flags for server integration
graph TB
subgraph "Client Authentication"
A[Mac Client Login]
B[Authentication Challenge]
end
subgraph "AFP Daemon"
C[Authentication Handler]
D[UAM Module Loader]
E[Session Manager]
end
subgraph "UAM Modules"
F[DHX - Diffie-Hellman Exchange]
G[DHX2 - Enhanced DHX]
H[PAM - System Authentication]
I[Guest - Anonymous Access]
J[Randnum - Challenge/Response]
K[Kerberos - Enterprise Auth]
end
subgraph "Backend Systems"
L[Unix Password Database]
M[PAM Modules]
N[LDAP Directory]
O[Kerberos KDC]
end
A --> C
B --> C
C --> D
D --> F
D --> G
D --> H
D --> I
D --> J
D --> K
H --> M
K --> O
M --> L
M --> N
The UAM system implements sophisticated authentication flows with different state machines for each authentication method:
stateDiagram-v2
[*] --> Initialized
state "DHX/DHX2 Authentication" as DHX {
Initialized --> Challenge_Sent: DHX/DHX2 Method
Challenge_Sent --> Key_Exchange: Client Response
Key_Exchange --> Password_Verify: Shared Secret Computed
Password_Verify --> Authenticated: Password Valid
Password_Verify --> Failed: Wrong Password
}
state "PAM Authentication" as PAM {
Initialized --> PAM_Auth: PAM Method Selected
PAM_Auth --> PAM_Challenge: Multi-factor Required
PAM_Challenge --> PAM_Response: User Input
PAM_Response --> Authenticated: PAM Success
PAM_Auth --> Authenticated: Simple Auth Success
PAM_Auth --> Failed: PAM Failed
PAM_Challenge --> Failed: Challenge Failed
PAM_Response --> Failed: Response Invalid
}
state "Other Methods" as Other {
Initialized --> Guest_Access: Guest Method
Guest_Access --> Authenticated: Anonymous Access
Initialized --> Kerberos_Auth: Kerberos Method
Kerberos_Auth --> Ticket_Verify: Validate Ticket
Ticket_Verify --> Authenticated: Ticket Valid
Ticket_Verify --> Failed: Ticket Invalid
Initialized --> Randnum_Auth: Randnum Method
Randnum_Auth --> Challenge_Response: Send Challenge
Challenge_Response --> Authenticated: Correct Response
Challenge_Response --> Failed: Wrong Response
}
Failed --> [*]: Authentication Failed
Authenticated --> [*]: Success
note right of DHX
Secure key exchange
No password transmission
Replay attack prevention
end note
note right of PAM
System integration
Multi-factor support
Flexible backends
end note
sequenceDiagram
participant Client as Mac Client
participant AFP as AFP Layer
participant UAM as UAM Module
participant Backend as Auth Backend
participant System as Unix System
Note over Client,System: DHX Authentication Flow
Client->>AFP: FPLogin (DHX method)
AFP->>UAM: Load DHX module
UAM->>UAM: Generate DH parameters
UAM->>Client: DH public key + challenge
Client->>Client: Compute shared secret
Client->>UAM: Encrypted credentials
UAM->>UAM: Decrypt with shared secret
UAM->>System: Verify user/password
System-->>UAM: Auth result
UAM-->>AFP: Authentication status
AFP-->>Client: Login response
Note over Client,System: PAM Authentication Flow
Client->>AFP: FPLogin (PAM method)
AFP->>UAM: Load PAM module
UAM->>Backend: PAM authentication
Backend->>System: System auth (LDAP/DB)
System-->>Backend: Auth result
Backend-->>UAM: PAM result
UAM-->>AFP: Authentication status
AFP-->>Client: Login response
Note over Client,System: Kerberos Authentication Flow
Client->>AFP: FPLogin (Kerberos method)
AFP->>UAM: Load Kerberos module
Client->>UAM: Kerberos ticket
UAM->>Backend: Verify ticket with KDC
Backend-->>UAM: Ticket validation
UAM-->>AFP: Authentication status
AFP-->>Client: Login response
-
etc/uams/uams_dhx_pam.c
- DHX with PAM backend authentication -
etc/uams/uams_dhx2_pam.c
- DHX2 with PAM backend authentication -
etc/uams/uams_pam.c
- Direct PAM authentication module -
etc/uams/uams_guest.c
- Guest/anonymous authentication module -
etc/uams/uams_gss.c
- Kerberos/GSSAPI authentication module -
etc/uams/uams_randnum.c
- Challenge/response authentication module
DHX provides secure password authentication using Diffie-Hellman key exchange.
Implementation Files:
-
etc/uams/uams_dhx_pam.c
- DHX implementation with PAM backend -
etc/uams/uams_dhx_pam.c
- DHX implementation with PAM backend -
etc/uams/uams_dhx_passwd.c
- DHX implementation with passwd backend
- Key Exchange: Establishes shared secret without transmitting passwords
- Challenge/Response: Uses random challenges to prevent replay attacks
- Password Encryption: Encrypts passwords using the shared secret
stateDiagram-v2
[*] --> DHX_INIT
DHX_INIT --> DHX_PARAMS_SENT: Send DH parameters
DHX_PARAMS_SENT --> DHX_KEY_COMPUTED: Receive client key
DHX_KEY_COMPUTED --> DHX_CHALLENGE_SENT: Send random challenge
DHX_CHALLENGE_SENT --> DHX_RESPONSE_RECEIVED: Receive encrypted response
DHX_RESPONSE_RECEIVED --> DHX_VERIFIED: Decrypt & verify
DHX_VERIFIED --> DHX_AUTHENTICATED: Password match
DHX_VERIFIED --> DHX_FAILED: Password mismatch
DHX_AUTHENTICATED --> [*]: Success
DHX_FAILED --> [*]: Authentication failed
note right of DHX_KEY_COMPUTED
Shared secret computed
using DH algorithm
end note
note right of DHX_RESPONSE_RECEIVED
Encrypted password +
challenge response
end note
// DHX UAM structure
struct dhx_context {
DH *dh; // Diffie-Hellman parameters
uint8_t *shared_secret; // Computed shared secret
size_t secret_len; // Secret length
uint8_t challenge[16]; // Random challenge
char username[256]; // Authenticated username
bool authenticated; // Authentication status
};
// DHX authentication flow
static int dhx_login(void *obj, struct passwd **uam_pwd,
char *ibuf, size_t ibuflen,
char *rbuf, size_t *rbuflen) {
struct dhx_context *ctx = (struct dhx_context *)obj;
int ret;
switch (ctx->state) {
case DHX_INIT:
ret = dhx_setup_exchange(ctx, ibuf, ibuflen, rbuf, rbuflen);
ctx->state = DHX_CHALLENGE;
break;
case DHX_CHALLENGE:
ret = dhx_verify_response(ctx, ibuf, ibuflen, rbuf, rbuflen);
if (ret == 0) {
ctx->authenticated = true;
*uam_pwd = getpwnam(ctx->username);
}
break;
default:
ret = AFPERR_BADUAM;
}
return ret;
}
DHX2 improves upon DHX with better security and support for longer passwords.
Implementation Files:
-
etc/uams/uams_dhx2_pam.c
- DHX2 implementation with PAM backend -
etc/uams/uams_dhx2_pam.c
- DHX2 implementation with PAM backend -
etc/uams/uams_dhx2_passwd.c
- DHX2 implementation with passwd backend
- Larger Key Size: Uses 512-bit or 1024-bit DH parameters
- Better Hashing: Uses SHA-1 instead of MD5
- Extended Password Support: Supports passwords longer than 8 characters
- Unicode Support: Handles UTF-8 encoded passwords
// DHX2 uses larger DH parameters
static DH *dhx2_generate_params(void) {
DH *dh = DH_new();
BIGNUM *p, *g;
// Use 1024-bit prime (vs 512-bit in DHX)
p = BN_new();
g = BN_new();
BN_hex2bn(&p, DHX2_1024_PRIME);
BN_set_word(g, DHX2_GENERATOR);
DH_set0_pqg(dh, p, NULL, g);
return dh;
}
// DHX2 password hashing with SHA-1
static int dhx2_hash_password(const char *password,
const uint8_t *challenge,
uint8_t *hash) {
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, password, strlen(password));
SHA1_Update(&ctx, challenge, 16);
SHA1_Final(hash, &ctx);
return 0;
}
PAM integration allows Netatalk to use system authentication mechanisms.
Implementation Files:
-
etc/uams/uams_pam.c
- Direct PAM authentication implementation -
etc/uams/uams_dhx_pam.c
- DHX with PAM backend integration -
etc/uams/uams_dhx2_pam.c
- DHX2 with PAM backend integration -
libatalk/util/
- PAM conversation and utility functions
// PAM authentication implementation
static int pam_authenticate_user(const char *username, const char *password) {
pam_handle_t *pamh = NULL;
struct pam_conv conv = {
.conv = pam_conversation,
.appdata_ptr = (void *)password
};
int ret;
// Start PAM transaction
ret = pam_start("netatalk", username, &conv, &pamh);
if (ret != PAM_SUCCESS) {
LOG(log_error, "PAM start failed: %s", pam_strerror(pamh, ret));
return -1;
}
// Authenticate user
ret = pam_authenticate(pamh, 0);
if (ret != PAM_SUCCESS) {
LOG(log_info, "PAM authentication failed for user %s: %s",
username, pam_strerror(pamh, ret));
pam_end(pamh, ret);
return -1;
}
// Check account validity
ret = pam_acct_mgmt(pamh, 0);
if (ret != PAM_SUCCESS) {
LOG(log_warning, "PAM account check failed for user %s: %s",
username, pam_strerror(pamh, ret));
pam_end(pamh, ret);
return -1;
}
pam_end(pamh, PAM_SUCCESS);
return 0;
}
// PAM conversation function
static int pam_conversation(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr) {
const char *password = (const char *)appdata_ptr;
struct pam_response *reply;
int i;
reply = calloc(num_msg, sizeof(struct pam_response));
if (reply == NULL) {
return PAM_CONV_ERR;
}
for (i = 0; i < num_msg; i++) {
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
// Password prompt
reply[i].resp = strdup(password);
break;
case PAM_PROMPT_ECHO_ON:
// Username prompt (shouldn't happen in our case)
reply[i].resp = NULL;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
// Information messages
reply[i].resp = NULL;
break;
default:
free(reply);
return PAM_CONV_ERR;
}
}
*resp = reply;
return PAM_SUCCESS;
}
Provides anonymous access for public volumes.
Implementation Files:
-
etc/uams/uams_guest.c
- Guest authentication module implementation -
libatalk/util/
- Guest session management utilities
// Guest UAM implementation
static int guest_login(void *obj, struct passwd **uam_pwd,
char *ibuf, size_t ibuflen,
char *rbuf, size_t *rbuflen) {
struct passwd *guest_pwd;
// Look up configured guest user
guest_pwd = getpwnam(guest_account);
if (guest_pwd == NULL) {
LOG(log_error, "Guest account '%s' not found", guest_account);
return AFPERR_BADUAM;
}
// Set up guest session
*uam_pwd = guest_pwd;
*rbuflen = 0; // No response data needed
LOG(log_info, "Guest login successful");
return AFP_OK;
}
Enterprise authentication using Kerberos tickets.
Implementation Files:
-
etc/uams/uams_gss.c
- Kerberos/GSSAPI authentication implementation -
libatalk/util/gss_auth.c
- GSS-API utilities and ticket validation -
etc/uams/gss_util.c
- Kerberos-specific utility functions
// Kerberos UAM implementation
static int gss_authenticate(void *obj, struct passwd **uam_pwd,
char *ibuf, size_t ibuflen,
char *rbuf, size_t *rbuflen) {
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
gss_name_t client_name = GSS_C_NO_NAME;
gss_buffer_desc input_token, output_token;
gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
OM_uint32 major_status, minor_status;
char *username = NULL;
int ret = AFPERR_BADUAM;
// Set up input token from client
input_token.value = ibuf;
input_token.length = ibuflen;
// Accept security context
major_status = gss_accept_sec_context(&minor_status,
&context,
server_creds,
&input_token,
GSS_C_NO_CHANNEL_BINDINGS,
&client_name,
NULL,
&output_token,
NULL,
NULL,
NULL);
if (major_status == GSS_S_COMPLETE) {
// Extract username from authenticated principal
gss_buffer_desc name_buffer;
major_status = gss_display_name(&minor_status, client_name,
&name_buffer, NULL);
if (major_status == GSS_S_COMPLETE) {
username = strndup(name_buffer.value, name_buffer.length);
gss_release_buffer(&minor_status, &name_buffer);
// Look up user account
*uam_pwd = getpwnam(username);
if (*uam_pwd != NULL) {
ret = AFP_OK;
LOG(log_info, "Kerberos authentication successful for %s",
username);
}
}
}
// Send response token if available
if (output_token.length > 0) {
memcpy(rbuf, output_token.value, output_token.length);
*rbuflen = output_token.length;
gss_release_buffer(&minor_status, &output_token);
}
// Cleanup
if (client_name != GSS_C_NO_NAME) {
gss_release_name(&minor_status, &client_name);
}
if (context != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
}
if (username) {
free(username);
}
return ret;
}
// UAM module structure
struct uam_module {
char *name; // Module name
void *handle; // Dynamic library handle
struct uam_export *uam_fcns;// Exported functions
int type; // Authentication type
struct uam_module *next; // Next module in list
};
// Load UAM module
static struct uam_module *load_uam_module(const char *path, const char *name) {
struct uam_module *mod;
void *handle;
struct uam_export *(*uam_attach)(void);
// Load dynamic library
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
LOG(log_error, "Failed to load UAM module %s: %s", path, dlerror());
return NULL;
}
// Get module attachment function
uam_attach = dlsym(handle, "uam_attach");
if (uam_attach == NULL) {
LOG(log_error, "UAM module %s missing uam_attach function", name);
dlclose(handle);
return NULL;
}
// Create module structure
mod = calloc(1, sizeof(struct uam_module));
if (mod == NULL) {
dlclose(handle);
return NULL;
}
mod->name = strdup(name);
mod->handle = handle;
mod->uam_fcns = uam_attach();
if (mod->uam_fcns == NULL) {
LOG(log_error, "UAM module %s attachment failed", name);
free(mod->name);
free(mod);
dlclose(handle);
return NULL;
}
LOG(log_info, "Loaded UAM module: %s", name);
return mod;
}
// UAM registration functions (from include/atalk/uam.h)
extern UAM_MODULE_EXPORT int uam_register(const int, const char *, const char *, ...);
extern UAM_MODULE_EXPORT void uam_unregister(const int, const char *);
// Helper functions
extern UAM_MODULE_EXPORT struct passwd *uam_getname(void *, char *, const int);
extern UAM_MODULE_EXPORT int uam_checkuser(const struct passwd *);
// AFP helper functions
extern UAM_MODULE_EXPORT int uam_afp_read(void *, char *, size_t *,
int (*)(void *, void *, const int));
extern UAM_MODULE_EXPORT int uam_afpserver_option(void *, const int, void *, size_t *);
// UAM export structure (from include/atalk/uam.h)
struct uam_export {
int uam_type; // Module type (SERVER=1, CLIENT=2)
int uam_version; // UAM module version (currently 1)
int (*uam_setup)(void *, const char *); // Setup function pointer
void (*uam_cleanup)(void); // Cleanup function pointer
};
// UAM module types
#define UAM_MODULE_SERVER 1 // Server-side authentication module
#define UAM_MODULE_CLIENT 2 // Client-side authentication module
#define UAM_MODULE_VERSION 1 // Current UAM API version
// UAM server authentication types
#define UAM_SERVER_LOGIN (1 << 0) // Standard login authentication
#define UAM_SERVER_CHANGEPW (1 << 1) // Password change capability
#define UAM_SERVER_PRINTAUTH (1 << 2) // Print authentication
#define UAM_SERVER_LOGIN_EXT (1 << 3) // Extended login authentication
// Register available UAMs with AFP daemon
static int register_uams(void) {
struct uam_module *mod;
int count = 0;
for (mod = uam_modules; mod != NULL; mod = mod->next) {
if (mod->uam_fcns && mod->uam_fcns->uam_setup) {
if (mod->uam_fcns->uam_setup() == 0) {
LOG(log_info, "Registered UAM: %s", mod->name);
count++;
} else {
LOG(log_warning, "UAM setup failed: %s", mod->name);
}
}
}
LOG(log_info, "Registered %d UAM modules", count);
return count;
}
The UAM system supports extensive configuration options through bitfield flags:
// UAM option flags (from include/atalk/uam.h)
#define UAM_OPTION_USERNAME (1 << 0) // Get space for username
#define UAM_OPTION_GUEST (1 << 1) // Get guest user
#define UAM_OPTION_PASSWDOPT (1 << 2) // Get the password file
#define UAM_OPTION_SIGNATURE (1 << 3) // Get server signature
#define UAM_OPTION_RANDNUM (1 << 4) // Request a random number
#define UAM_OPTION_HOSTNAME (1 << 5) // Get host name
#define UAM_OPTION_COOKIE (1 << 6) // Cookie handle
#define UAM_OPTION_PROTOCOL (1 << 7) // DSI or ASP protocol info
#define UAM_OPTION_CLIENTNAME (1 << 8) // Get client IP address
#define UAM_OPTION_KRB5SERVICE (1 << 9) // Service name for krb5 principal
#define UAM_OPTION_MACCHARSET (1 << 10) // Mac charset handle
#define UAM_OPTION_UNIXCHARSET (1 << 11) // Unix charset handle
#define UAM_OPTION_SESSIONINFO (1 << 12) // Session info handle
#define UAM_OPTION_KRB5REALM (1 << 13) // Kerberos realm
#define UAM_OPTION_FQDN (1 << 14) // Fully qualified domain name
// Password-specific options
#define UAM_PASSWD_FILENAME (1 << 0) // Password filename
#define UAM_PASSWD_MINLENGTH (1 << 1) // Minimum password length
#define UAM_PASSWD_EXPIRETIME (1 << 3) // Password expiration (not implemented)
// Maximum username length
#define UAM_USERNAMELEN 255
// Session management structure (from include/atalk/uam.h)
#define SESSIONKEY_LEN 64
#define SESSIONTOKEN_LEN 8
struct session_info {
// Random session key for encryption
void *sessionkey; // Session key data
size_t sessionkey_len; // Session key length
// Kerberos/GSSAPI crypted key
void *cryptedkey; // Encrypted key data
size_t cryptedkey_len; // Encrypted key length
// Session token sent to client on FPGetSessionToken
void *sessiontoken; // Session token data
size_t sessiontoken_len; // Session token length
// Client identification buffer (idlen, id, boottime)
void *clientid; // Client ID buffer
size_t clientid_len; // Client ID buffer length
};
// Authentication session state
struct auth_session {
char username[UAM_USERNAMELEN + 1]; // Authenticated username
uid_t uid; // User ID
gid_t gid; // Primary group ID
gid_t *groups; // Supplementary groups
int ngroups; // Number of groups
// Authentication method info
char *uam_name; // UAM used for authentication
time_t login_time; // Login timestamp
time_t last_activity; // Last activity timestamp
// Session security context
struct session_info *session_info; // Session management data
bool authenticated; // Authentication status
bool admin; // Administrative privileges
};
// Initialize authentication session
static int init_auth_session(struct auth_session *session,
struct passwd *pwd, const char *uam_name) {
session->uid = pwd->pw_uid;
session->gid = pwd->pw_gid;
strncpy(session->username, pwd->pw_name, sizeof(session->username) - 1);
// Get supplementary groups
session->ngroups = NGROUPS_MAX;
session->groups = malloc(session->ngroups * sizeof(gid_t));
if (getgrouplist(pwd->pw_name, pwd->pw_gid,
session->groups, &session->ngroups) == -1) {
session->groups = realloc(session->groups,
session->ngroups * sizeof(gid_t));
getgrouplist(pwd->pw_name, pwd->pw_gid,
session->groups, &session->ngroups);
}
// Set authentication info
session->uam_name = strdup(uam_name);
session->login_time = time(NULL);
session->last_activity = session->login_time;
session->authenticated = true;
session->admin = (session->uid == 0);
return 0;
}
// Check user access to volume
int check_volume_access(struct auth_session *session, struct vol *vol) {
struct stat st;
// Check if volume path is accessible
if (stat(vol->v_path, &st) != 0) {
return AFPERR_NOOBJ;
}
// Check basic read access
if (access(vol->v_path, R_OK) != 0) {
// Check if user is in volume's allowed group
if (vol->v_allowed_gid != (gid_t)-1) {
for (int i = 0; i < session->ngroups; i++) {
if (session->groups[i] == vol->v_allowed_gid) {
return AFP_OK;
}
}
}
return AFPERR_ACCESS;
}
return AFP_OK;
}
// Check file/directory permissions
int check_file_access(struct auth_session *session, const char *path, int mode) {
struct stat st;
if (stat(path, &st) != 0) {
return AFPERR_NOOBJ;
}
// Root can access everything
if (session->uid == 0) {
return AFP_OK;
}
// Check owner permissions
if (st.st_uid == session->uid) {
if ((mode & R_OK) && !(st.st_mode & S_IRUSR)) return AFPERR_ACCESS;
if ((mode & W_OK) && !(st.st_mode & S_IWUSR)) return AFPERR_ACCESS;
if ((mode & X_OK) && !(st.st_mode & S_IXUSR)) return AFPERR_ACCESS;
return AFP_OK;
}
// Check group permissions
for (int i = 0; i < session->ngroups; i++) {
if (session->groups[i] == st.st_gid) {
if ((mode & R_OK) && !(st.st_mode & S_IRGRP)) return AFPERR_ACCESS;
if ((mode & W_OK) && !(st.st_mode & S_IWGRP)) return AFPERR_ACCESS;
if ((mode & X_OK) && !(st.st_mode & S_IXGRP)) return AFPERR_ACCESS;
return AFP_OK;
}
}
// Check other permissions
if ((mode & R_OK) && !(st.st_mode & S_IROTH)) return AFPERR_ACCESS;
if ((mode & W_OK) && !(st.st_mode & S_IWOTH)) return AFPERR_ACCESS;
if ((mode & X_OK) && !(st.st_mode & S_IXOTH)) return AFPERR_ACCESS;
return AFP_OK;
}
# netatalk.conf UAM settings
[Global]
uam list = uams_dhx2.so uams_dhx.so uams_pam.so uams_guest.so
uam path = /usr/local/lib/netatalk/
# Security settings
admin group = @admin
guest account = nobody
login message = "Welcome to Netatalk Server"
# Authentication options
passwd file = /etc/netatalk/afppasswd
passwd minlen = 6
save password = yes
- UAM Selection: Choose appropriate authentication methods for security requirements
- Guest Access: Disable guest access for sensitive volumes
- Password Policies: Enforce strong password requirements
- Session Management: Implement proper session timeout and cleanup
- Audit Trail: Log authentication attempts and access patterns
The authentication system provides flexible, secure user authentication while maintaining compatibility with various Mac client versions and enterprise authentication systems. Its modular design allows organizations to adapt authentication methods to their specific security requirements and infrastructure.
Resources
OS Specific Guides
- Installing Netatalk on Alpine Linux
- Installing Netatalk on Debian Linux
- Installing Netatalk on Fedora Linux
- Installing Netatalk on FreeBSD
- Installing Netatalk on macOS
- Installing Netatalk on NetBSD
- Installing Netatalk on OmniOS
- Installing Netatalk on OpenBSD
- Installing Netatalk on OpenIndiana
- Installing Netatalk on openSUSE
- Installing Netatalk on Solaris
- Installing Netatalk on Ubuntu
Technical Docs
- CatalogSearch
- Kerberos
- Special Files and Folders
- Spotlight
- AppleTalk Kernel Module
- Print Server
- MacIP Gateway
- MySQL CNID Backend
Development