/* pgp passwd */ static int pgp_login(void *obj, struct passwd **uam_pwd, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { size_t len, i; char *name; *rbuflen = 0; if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0) return AFPERR_PARAM; len = (unsigned char) *ibuf++; if ( len > i ) { return( AFPERR_PARAM ); } memcpy(name, ibuf, len ); ibuf += len; name[ len ] = '\0'; if ((unsigned long) ibuf & 1) /* padding */ ++ibuf; if (( pgppwd = uam_getname(obj, name, i)) == NULL ) { return AFPERR_PARAM; } LOG(log_info, logtype_uams, "pgp login: %s", name); if (uam_checkuser(pgppwd) < 0) return AFPERR_NOTAUTH; /* get the challenge */ len = (unsigned char) *ibuf++; /* challenge */ /* get the signature. it's always 16 bytes. */ if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, (void *) &name, NULL) < 0) { *rbuflen = 0; goto pgp_fail; } memcpy(rbuf + KEYSIZE, name, KEYSIZE); pgp_fail: return AFPERR_PARAM; }
static int gss_logincont(void *obj, struct passwd **uam_pwd, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { struct passwd *pwd = NULL; uint16_t login_id; char *username; uint16_t ticket_len; char *p; int rblen; size_t userlen; struct session_info *sinfo; /* Apple's AFP 3.1 documentation specifies that this command * takes the following format: * pad (byte) * id returned in LoginExt response (uint16_t) * username (format unspecified) * padded, when necessary, to end on an even boundary * ticket length (uint16_t) * ticket */ /* Observation of AFP clients in the wild indicate that the actual * format of this request is as follows: * pad (byte) [consumed before login_ext is called] * ?? (byte) - always observed to be 0 * id returned in LoginExt response (uint16_t) * username, encoding unspecified, null terminated C string, * padded when the terminating null is an even numbered byte. * The packet is formated such that the username begins on an * odd numbered byte. Eg if the username is 3 characters and the * terminating null makes 4, expect to pad the the result. * The encoding of this string is unknown. * ticket length (uint16_t) * ticket */ rblen = *rbuflen = 0; if (ibuflen < 1 +sizeof(login_id)) { LOG_LOGINCONT(log_info, "received incomplete packet"); return AFPERR_PARAM; } ibuf++, ibuflen--; /* ?? */ /* 2 byte ID from LoginExt -- always '00 01' in this implementation */ memcpy(&login_id, ibuf, sizeof(login_id)); ibuf += sizeof(login_id), ibuflen -= sizeof(login_id); login_id = ntohs(login_id); /* get the username buffer from apfd */ if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &userlen) < 0) return AFPERR_MISC; /* get the session_info structure from afpd. We need the session key */ if (uam_afpserver_option(obj, UAM_OPTION_SESSIONINFO, &sinfo, NULL) < 0) return AFPERR_MISC; if (sinfo->sessionkey == NULL || sinfo->sessionkey_len == 0) { /* Should never happen. Most likely way too old afpd version */ LOG_LOGINCONT(log_error, "internal error: afpd's sessionkey not set"); return AFPERR_MISC; } /* We skip past the 'username' parameter because all that matters is the ticket */ p = ibuf; while ( *ibuf && ibuflen ) { ibuf++, ibuflen--; } if (ibuflen < 4) { LOG_LOGINCONT(log_info, "user is %s, no ticket", p); return AFPERR_PARAM; } ibuf++, ibuflen--; /* null termination */ if ((ibuf - p + 1) % 2) ibuf++, ibuflen--; /* deal with potential padding */ LOG_LOGINCONT(log_debug, "client thinks user is %s", p); /* get the length of the ticket the client sends us */ memcpy(&ticket_len, ibuf, sizeof(ticket_len)); ibuf += sizeof(ticket_len); ibuflen -= sizeof(ticket_len); ticket_len = ntohs(ticket_len); /* a little bounds checking */ if (ticket_len > ibuflen) { LOG_LOGINCONT(log_info, "invalid ticket length (%u > %u)", ticket_len, ibuflen); return AFPERR_PARAM; } /* now try to authenticate */ if (do_gss_auth(obj, ibuf, ticket_len, rbuf, &rblen, username, userlen, sinfo)) { LOG_LOGINCONT(log_info, "do_gss_auth() failed" ); *rbuflen = 0; return AFPERR_MISC; } /* We use the username we got back from the gssapi client_name. Should we compare this to the username the client sent in the clear? We know the character encoding of the cleartext username (UTF8), what encoding is the gssapi name in? */ if ((pwd = uam_getname( obj, username, userlen )) == NULL) { LOG_LOGINCONT(log_info, "uam_getname() failed for %s", username); return AFPERR_NOTAUTH; } if (uam_checkuser(pwd) < 0) { LOG_LOGINCONT(log_info, "`%s'' not a valid user", username); return AFPERR_NOTAUTH; } *rbuflen = rblen; *uam_pwd = pwd; return AFP_OK; }
/* get the principal from afpd and import it into server_name */ static int get_afpd_principal(void *obj, gss_name_t *server_name) { OM_uint32 major_status = 0, minor_status = 0; char *fqdn, *service, *principal, *p; size_t fqdnlen=0, servicelen=0; size_t principal_length; gss_buffer_desc s_princ_buffer; /* get all the required information from afpd */ if (uam_afpserver_option(obj, UAM_OPTION_FQDN, (void*) &fqdn, &fqdnlen) < 0) return 1; LOG(log_debug, logtype_uams, "get_afpd_principal: fqdn: %s", fqdn); if (uam_afpserver_option(obj, UAM_OPTION_KRB5SERVICE, (void *)&service, &servicelen) < 0) return 1; LOG(log_debug, logtype_uams, "get_afpd_principal: service: %s", service); /* we need all the info, log error and return if one's missing */ if (!service || !servicelen || !fqdn || !fqdnlen) { LOG(log_error, logtype_uams, "get_afpd_principal: could not retrieve required information from afpd."); return 1; } /* allocate memory to hold the temporary principal string */ principal_length = servicelen + 1 + fqdnlen + 1; if ( NULL == (principal = (char*) malloc( principal_length)) ) { LOG(log_error, logtype_uams, "get_afpd_principal: out of memory allocating %u bytes", principal_length); return 1; } /* * Build the principal string. * Format: 'service@fqdn' */ strlcpy( principal, service, principal_length); strlcat( principal, "@", principal_length); /* * The fqdn we get from afpd may contain a port. * We need to strip the port from fqdn for principal. */ if ((p = strchr(fqdn, ':'))) *p = '\0'; strlcat( principal, fqdn, principal_length); if (p) *p = ':'; /* * Import our principal into the gssapi internal representation * stored in server_name. */ s_princ_buffer.value = principal; s_princ_buffer.length = strlen( principal ) + 1; LOG(log_debug, logtype_uams, "get_afpd_principal: importing principal `%s'", principal); major_status = gss_import_name( &minor_status, &s_princ_buffer, GSS_C_NT_HOSTBASED_SERVICE, server_name ); /* * Get rid of malloc'ed memmory. * Don't release the s_princ_buffer, we free principal instead. */ free(principal); if (major_status != GSS_S_COMPLETE) { /* Importing our service principal failed, bail out. */ log_status( "import_principal", major_status, minor_status ); return 1; } return 0; }