Skip to content

Dev Docs Components Auth

Andy Lemin edited this page Aug 16, 2025 · 2 revisions

WIP - ALL LINKS IN THIS WIKI STRUCTURE ARE CURRENTLY BROKEN DURING WIKI MIGRATION

THESE ARE COMMUNITY DOCS

Authentication System (UAMs)

Overview

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.

Implementation Files

  • 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

Architecture

UAM Pluggable Architecture

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
Loading

Implementation Architecture

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

UAM Module System

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
Loading

UAM Authentication State Machine

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
Loading

UAM Authentication Flow Sequence

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
Loading

UAM Module Types

Implementation Files for UAM Modules

  • 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

1. DHX (Diffie-Hellman Exchange)

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

Security Features

  • 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

DHX Authentication State Flow

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
Loading

Implementation

// 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;
}

2. DHX2 (Enhanced DHX)

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

Enhancements

  • 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

Key Differences from DHX

// 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;
}

3. PAM (Pluggable Authentication Modules)

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 Integration

// 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;
}

4. Guest Authentication

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;
}

5. Kerberos/GSSAPI Authentication

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 Loading and Management

Dynamic Module Loading

// 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 and Helper Functions

// 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;
}

Session Management

UAM Option Flags

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 Information Structure

// 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;
}

Access Control Integration

Permission Checking

// 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;
}

Configuration and Security

UAM Configuration

# 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

Security Best Practices

  1. UAM Selection: Choose appropriate authentication methods for security requirements
  2. Guest Access: Disable guest access for sensitive volumes
  3. Password Policies: Enforce strong password requirements
  4. Session Management: Implement proper session timeout and cleanup
  5. 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.

Clone this wiki locally